This specification describes Data Integrity cryptosuites for use when generating a digital signature using the Elliptic Curve Digital Signature Algorithm (ECDSA).

Comments regarding this specification are welcome at any time. Please file issues directly on GitHub, or send them to public-vc-comments@w3.org if that is not possible. (subscribe, archives).

Introduction

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 secp256r1 terms with secp256k1 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

Terminology used throughout this document is defined in the Terminology section of the [[[VC-DATA-INTEGRITY]]] specification.

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 [[[#data-model]]] and [[[#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.

Data Model

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.

Verification Methods

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.

Multikey

The Multikey format, defined in [[[CID]]], 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 [[[CID]]]. 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 [[[CID]]]. 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 [[[CID]]]. 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 [[[CID]]]. 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.

Proof Representations

This section details the proof representation formats that are defined by this specification.

DataIntegrityProof

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 [[[VC-DATA-INTEGRITY-1.1#create-proof]]] or [[[VC-DATA-INTEGRITY-1.1#create-base-proof]]], or [[[VC-DATA-INTEGRITY-1.1#verify-derived-proof]]].

{
  "@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"
  }
}
          

Algorithms

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.

Instantiate Cryptosuite

This algorithm is used to configure a cryptographic suite to be used by the Add Proof and Verify Proof functions in [[[VC-DATA-INTEGRITY]]]. The algorithm takes an options object ([=map=] |options|) as input and returns a [=data integrity cryptographic suite instance|cryptosuite instance=] ([=struct=] |cryptosuite|).

  1. Initialize |cryptosuite| to an empty [=struct=].
  2. If |options|.|type| does not equal `DataIntegrityProof`, return |cryptosuite|.
  3. If |options|.|cryptosuite| is `ecdsa-rdfc-2019` or `ecdsa-jcs-2019` then:
    1. Set the values of the parameters `canonScheme`, `hashName`, `sigFunc`, `verifyFunc`, and `proofEncoding` as indicated in [[[#ECDSA-Cryptosuites]]] and [[[#ECDSASuiteTable]]].
    2. Set |cryptosuite|.|createProof| to the algorithm in Section [[[VC-DATA-INTEGRITY-1.1#create-proof]]] passing in the above parameters.
    3. Set |cryptosuite|.|verifyProof| to the algorithm in Section [[[VC-DATA-INTEGRITY-1.1#verify-proof-0]]] passing in the above parameters.
  4. If |options|.|cryptosuite| is `ecdsa-sd-2023` then:
    1. Set the values of the parameters `approach`, `hashName`, `sigFunc`, and `verifyFunc`, as indicated in section [[[#selective-disclosure-ecdsa-cryptosuites]]].
    2. Set |cryptosuite|.|createBaseProof| to the algorithm in Section [[[VC-DATA-INTEGRITY-1.1#create-base-proof]]] passing in the above parameters.
    3. Set |cryptosuite|.|addDerivedProof| to the algorithm in Section [[[VC-DATA-INTEGRITY-1.1#add-derived-proof]]] passing in the above parameters.
    4. Set |cryptosuite|.|verifyDerivedProof| to the algorithm in Section [[[VC-DATA-INTEGRITY-1.1#verify-derived-proof]]] passing in the above parameters.
  5. Return |cryptosuite|.

ECDSA Cryptosuites (full disclosure)

The full disclosure ECDSA cryptosuites defined in this specification make use of [[[VC-DATA-INTEGRITY-1.1#CryptosuiteCommonAlgorithms]]] from the [[!VC-DATA-INTEGRITY-1.1]] specification. All ECDSA cryptosuites make use of the Elliptic Curve Digital Signature Algorithm (ECDSA) [[FIPS-186-5]], and the corresponding verification algorithm, using either the [[NIST-SP-800-186]] P-256 curve, or the P-384 curve.

The ECDSA cryptosuites defined in this specification use either the SHA-256 cryptographic hashing algorithm [[RFC6234]] when the P-256 curve is used, or the SHA-384 hashing algorithm when the P-384 curve is used. These correspond to a |hashName| parameter of `SHA-256` or `SHA-384` for use in [[[VC-DATA-INTEGRITY-1.1#CryptosuiteCommonAlgorithms]]]. Furthermore all ECDSA cryptosuites use base58-btc-encoded Multibase value for their proof, hence |proofEncoding| parameter is set to `base58` in [[[VC-DATA-INTEGRITY-1.1#CryptosuiteCommonAlgorithms]]].

For the P-256 curve, the raw private key size is 32 bytes, the raw public key size is 33 bytes, and the length of the raw signature is 64 bytes. For the P-384 curve, the raw private key size is 48 bytes, the raw public key size is 49 bytes, and the length of the raw signature is 96 bytes.

Supporting both Universal RDF Dataset Canonicalization Algorithm [[RDF-CANON]], "`rdfc`", and JSON Canonicalization Scheme [[RFC8785]], "`jcs`", leads to the family of EdDSA cryptosuites given in [[[#ECDSASuiteTable]]].

Supported EdDSA Cryptosuites.
Name Canonizalization Signature/Verification Hash
`ecdsa-rdfc-2019` RDFC Elliptic Curve Digital Signature Algorithm (ECDSA) [[FIPS-186-5]], P-256 curve SHA-256
`ecdsa-rdfc-2019` RDFC Elliptic Curve Digital Signature Algorithm (ECDSA) [[FIPS-186-5]], P-384 curve SHA-384
`ecdsa-jcs-2019` JCS Elliptic Curve Digital Signature Algorithm (ECDSA) [[FIPS-186-5]], P-256 curve SHA-256
`ecdsa-jcs-2019` JCS Elliptic Curve Digital Signature Algorithm (ECDSA) [[FIPS-186-5]], P-384 curve SHA-384

The choice of the P-256 or P-384 is made by the issuer, based on desired security strength with P-256 commonly used. The verifier can tell which curve was used (P-256 or P-384) by the length of the retrieved public key material.

Selective Disclosure ECDSA Cryptosuites

The [[VC-DATA-INTEGRITY-1.1]] specification defines [=selective disclosure=] and defines common algorithms for implementing [=selective disclosure=] where the signature scheme does not natively support it. Two general approaches are defined (1) Signed Individual Claims ([=SIC=]) and (2) Salted Hash of Claims ([=SHoC=]). The size of the signature impacts the overall base and derived proof sizes as indicated in [[[VC-DATA-INTEGRITY-1.1#SDApproachTable]]]. For short signature sizes such as those produced by ECDSA algorithms the [=SIC=] approach would be used.

The selective disclosure cryptosuites defined in this specification are listed in [[[#ECDSA-SD-SuiteTable]]]. Note that all selective disclosure cryptosuites utilize the advanced features of [[RDF-CANON]].

Supported EdDSA Selective Disclosure Cryptosuites.
Name Approach Signature/Verification Hash
`ecdsa-sd-2023` [=SIC=] Elliptic Curve Digital Signature Algorithm (ECDSA) [[FIPS-186-5]], P-256 curve SHA-256

Security Considerations

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.

Choice of ECDSA and Parameters

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.

Implementation Considerations for ECDSA Algorithms

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.

Key Management

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]].

Privacy Considerations

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.

Unlinkable Disclosure

The cryptographic suites described in this specification do not support [=unlinkable disclosure=]. If [=unlinkable disclosure=] is of interest, the [[[?VC-DI-BBS]]] specification provides an unlinkable digital signature mechanism.

Test Vectors

All test vectors are produced using deterministic ECDSA. The implementation was validated against the test vectors in [[RFC6979]].

Representation: ecdsa-rdfc-2019, with curve P-256

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.

        

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.



        



        


        

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.



        


        


        

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.



        


        


        

Assemble the signed credential with the following two steps:

  1. Add the proofValue field with the previously computed base-58-btc value to the proof options document.
  2. Set the proof field of the credential to the augmented proof option document.

      

Enhanced Example for Representation: ecdsa-rdfc-2019, with curve P-256

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.

        

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.



        



        


        

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.



        


        


        

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.



        


        


        

Assemble the signed credential with the following two steps:

  1. Add the proofValue field with the previously computed base-58-btc value to the proof options document.
  2. Set the proof field of the credential to the augmented proof option document.

      

Representation: ecdsa-rdfc-2019, with curve P-384

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.

        

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.



        



        


        

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.



        


        


        

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.



        


        


        

Assemble the signed credential with the following two steps:

  1. Add the proofValue field with the previously computed base-58-btc value to the proof options document.
  2. Set the proof field of the credential to the augmented proof option document.

      

Enhanced Example for Representation: ecdsa-rdfc-2019, with curve P-384

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.

        

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.



        



        


        

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.



        


        


        

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.



        


        


        

Assemble the signed credential with the following two steps:

  1. Add the proofValue field with the previously computed base-58-btc value to the proof options document.
  2. Set the proof field of the credential to the augmented proof option document.

      

Representation: ecdsa-jcs-2019 with curve P-256

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.

        

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.



        



        


        

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.



        


        


        

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.



        


        


        

Assemble the signed credential with the following three steps:

  1. Add the proofValue field with the previously computed base-58-btc value to the proof options document.
  2. Set the proof options @context field to the value of the unsecuredDocument.@context.
  3. Set the proof field of the credential to the augmented proof option document.

      

Representation: ecdsa-jcs-2019 with curve P-384

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.

        

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.



        



        


        

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.



        


        


        

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.



        


        


        

Assemble the signed credential with the following three steps:

  1. Add the proofValue field with the previously computed base-58-btc value to the proof options document.
  2. Set the proof options @context field to the value of the unsecuredDocument.@context.
  3. Set the proof field of the credential to the augmented proof option document.

      

Representation: ecdsa-sd-2023

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).

Base Proof

In order to add a selective disclosure base proof to a document the issuer needs the following cryptographic key material:

  1. The issuers private/public key pair, i.e., the key pair corresponding to the verification method that will be part of the proof.
  2. A per proof private/public key pair created by the issuer just for this proof. This is an ephemeral, single use key pair where the private key is not kept after the proof has been generated.
  3. An HMAC key. This used to randomize the order of the blank node ids to avoid potential information leakage from the blank node id ordering. This is used only once and is shared between issuer and holder. The HMAC in this case is functioning as a pseudorandom function (PRF).

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.

          

In our scenario a person will be issued an employment authorization document as shown below.


          

The mandatory information as specified by the issuer is specified via an array of JSON pointers as shown below.


          

The result of applying the above JSON pointers to the employment authorization document is shown below.


          

Transformation of the unsigned document begins with canonicalizing the document as shown below.


          

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.


          

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.


          

The next step is to create the base proof configuration and canonicalize it. This is shown in the following two examples.


          

          

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.


          

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.


          

Finally, the values above are run through the algorithm of [[[VC-DATA-INTEGRITY-1.1#SerializeBase-SIC]]] to produce the `proofValue` which is used in the signed based document shown below.


        

Derived Proof

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 [[[#base-proof]]] above. The first step is to run the algorithm of [[[VC-DATA-INTEGRITY-1.1#ParseBase-SIC]]] to recover `baseSignature`, `publicKey`, `hmacKey`, `signatures`, and `mandatoryPointers` as shown below.


          

Next, the holder needs to indicate what, if anything else, they wish to reveal to the verifiers by specifying JSON pointers for selective disclosure.


          

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 [[[VC-DATA-INTEGRITY-1.1#selectjsonld]]] to give the result shown below.


          

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 [[[VC-DATA-INTEGRITY-1.1#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.


          

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.


          

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.


          

The last important piece of disclosure data is a mapping of canonical blank node ids to HMAC based ids, the `labelMap`, computed according to [[[VC-DATA-INTEGRITY-1.1#CreateDisclosureData]]]. This is shown below along with the rest of the disclosure data minus the reveal document.


          

Finally using the disclosure data above with the algorithm of Section [[[VC-DATA-INTEGRITY-1.1#SerializeDerived-SIC]]] we obtain the signed derived (reveal) document shown below.


        

Additional Example for Representation: ecdsa-sd-2023

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).

Base Proof

In order to add a selective disclosure base proof to a document the issuer needs the following cryptographic key material:

  1. The issuers private/public key pair, i.e., the key pair corresponding to the verification method that will be part of the proof.
  2. A per proof private/public key pair created by the issuer just for this proof. This is an ephemeral, single use key pair where the private key is not kept after the proof has been generated.
  3. An HMAC key. This used to randomize the order of the blank node ids to avoid potential information leakage from the blank node id ordering. This is used only once and is shared between issuer and holder. The HMAC in this case is functioning as a pseudorandom function (PRF).

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.

          

In our scenario a person will be issued a permanent resident credential as shown below.


          

The mandatory information as specified by the issuer is specified via an array of JSON pointers as shown below.


          

The result of applying the above JSON pointers to the permanent resident credential is shown below.


          

Transformation of the unsigned document begins with canonicalizing the document as shown below.


          

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.


          

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.


          

The next step is to create the base proof configuration and canonicalize it. This is shown in the following two examples.


          

          

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.


          

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.


          

Finally, the values above are run through the algorithm of Section [[[VC-DATA-INTEGRITY-1.1#SerializeBase-SIC]]] to produce the `proofValue` which is used in the signed based document shown below.


        

Derived Proof

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 [[[#base-proof]]] above. The first step is to run the algorithm of [[[VC-DATA-INTEGRITY-1.1#ParseBase-SIC]]] to recover `baseSignature`, `publicKey`, `hmacKey`, `signatures`, and `mandatoryPointers` as shown below.


          

Next, the holder needs to indicate what, if anything else, they wish to reveal to the verifiers by specifying JSON pointers for selective disclosure.


          

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 [[[VC-DATA-INTEGRITY-1.1#selectjsonld]]] to give the result shown below.


          

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 [[[VC-DATA-INTEGRITY-1.1#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.


          

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.


          

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.


          

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 [[[VC-DATA-INTEGRITY-1.1#CreateDisclosureData]]]. This is shown below along with the rest of the disclosure data minus the reveal document.


          

Finally using the disclosure data above with the algorithm of Section [[[VC-DATA-INTEGRITY-1.1#SerializeDerived-SIC]]] we obtain the signed derived (reveal) document shown below.


        

Revision History

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:

Changes since the First Public Working Draft:

Acknowledgements

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.