Verifiable Credential Barcodes v1.0

Embedding Verifiable Credentials in optical barcodes

W3C Working Draft

More details about this document
This version:
https://www.w3.org/TR/2026/WD-vc-barcodes-1.0-20260715/
Latest published version:
https://www.w3.org/TR/vc-barcodes-1.0/
Latest editor's draft:
https://w3c.github.io/vc-barcodes/
History:
https://www.w3.org/standards/history/vc-barcodes-1.0/
Commit history
Editors:
Wesley Smith (Digital Bazaar)
Elaine Wooton (Invited Expert)
Manu Sporny (Digital Bazaar)
Authors:
Manu Sporny (Digital Bazaar)
Dave Longley (Digital Bazaar)
Wesley Smith (Digital Bazaar)
Feedback:
GitHub w3c/vc-barcodes (pull requests, new issue, open issues)
Related Specifications
The Verifiable Credentials Data Model v2.0
Verifiable Credential Data Integrity v1.1
The Elliptic Curve Digital Signature Algorithm Cryptosuites v1.1
Compact Binary Object Representation for Linked Data v1.0

Abstract

This specification describes a mechanism to protect optical barcodes, such as those found on driver's licenses (PDF417) and travel documents (MRZ), using Verifiable Credentials [VC-DATA-MODEL-2.0]. The Verifiable Credential representations are compact enough such that they fit in under 150 bytes and can thus be integrated with traditional two-dimensional barcodes that are printed on physical cards using standard printing processes.

Status of This Document

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.

This document was published by the Verifiable Credentials Working Group as a Working Draft using the Recommendation track.

Publication as a Working Draft 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 a work in progress.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent that the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 18 August 2025 W3C Process Document.

1. Introduction

Physical credentials, such as driver's licenses, passports, and travel credentials often include machine-readable data that can be used to quickly read the information from the document. This information is encoded in formats such as PDF417 [ISO15438-2015], machine-readable zone (MRZ) [ICAO9303-3], and other optically scannable codes that are formatted in one-dimensional or two-dimensional "bars"; thus the term "barcode". This information is often not protected from tampering and the readily available barcode generation and scanning libraries mean that it is fairly trivial for anyone to generate these barcodes.

It is, therefore, useful for an issuer of these barcodes to protect the information contained within the barcode as well as the entity that generated the barcode.

The Verifiable Credentials Data Model v2.0 specification provides a global standard for expressing credential information, such as those in a driver's license or travel document. The Verifiable Credential Data Integrity 1.0 specification provides a global standard for securing credential information. These two specifications, when combined, provide a means of protecting credentials from tampering, expressing authorship of the credential, and providing the current status of a credential in a privacy-protecting manner. These data formats, however, tend to be too large to express in an optical barcode.

The Compact Binary Object Representation for Linked Data v1.0 specification provides a means of compressing secured verifiable credentials to the point at which it becomes feasible to express the information as an optical barcode, or embedded within an optical barcode.

This specification describes a mechanism to protect optical barcodes, such as those found on driver's licenses (PDF417) and travel documents (MRZ), by using a verifiable credential [VC-DATA-MODEL-2.0] to express information about either the barcode itself or the subject of the barcode. Next, this Verifiable Credential is secured using Data Integrity [VC-DATA-INTEGRITY], and then compressed using CBOR-LD [CBOR-LD].

There are two main mechanisms by which a Verifiable Credential can be used to protect a barcode:

Both use cases achieve authenticity, integrity, and tamper resistance over the data protected by the Verifiable Credential. Additionally, for use cases that require it, these Verifiable Credentials can be revoked or suspended on a per-barcode basis.

1.1 Introductory Examples

The following sections provide a few introductory examples of the ways this specification can be used to enhance existing physical credentials with digital signatures via verifiable credentials.

1.1.1 Driver's License

This section provides an example on how the technology in this specification can be utilized to secure the optical barcode on a driver's license that uses a PDF417 barcode. We start off with an example driver's license:

Picture of the front of a driver's license issued by the state of Utopia which contains a picture of the individual that is the subject of the driver's license along with their attributes, such as name, address, height, weight, eye color, and driving privileges.
Figure 1 The front of a driver's license issued by the state of Utopia.

The back of the driver's license contains a PDF417 barcode:

Picture of the back of a driver's license issued by the state of Utopia, containing usage rules as well as a PDF417 barcode that encodes much of the information displayed on the front of the card.
Figure 2 A back of a driver's license issued by the state of Utopia.

The PDF417 data contains information that is secured using the algorithms described in this specification. Namely, the PDF417 barcode contains a verifiable credential of the following form.

Example 1: Verifiable Credential embedded in the PDF417 barcode
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/vdl/v2",
    "https://w3id.org/vdl/utopia/v1"
  ],
  "type": [
    "VerifiableCredential",
    "OpticalBarcodeCredential"
  ],
  // the issuer value below is defined as a URL in the 'utopia/v1' context above
  "issuer": "did:web:dmv.utopia.example",
  "credentialStatus": {
    "type": "TerseBitstringStatusListEntry",
    "terseStatusListBaseUrl": "https://dmv.utopia.gov/statuses/12345/status-lists"
    "terseStatusListIndex": 123567890
  },
  "credentialSubject": {
    "type": "AamvaDriversLicenseScannableInformation",
    "protectedComponentIndex": "uP_BA"
  },
  "proof": {
    "type": "DataIntegrity",
    "cryptosuite": "ecdsa-xi-2023",
    // the public key below is defined as a URL in the 'utopia/v1' context above
    "verificationMethod": "did:web:dmv.utopia.example#key-1",
    "proofPurpose": "assertionMethod",
    "proofValue": "z4peo48uwK2EF4Fta8P...HzQMDYJ34r9gL"
  }
}

The verifiable credential above is then compressed using [CBOR-LD] to the following output (in CBOR Diagnostic Notation):

Example 2: CBOR-LD compressed Verifiable Credential (145 bytes)
1281{
  1 => [ 32768, 32769, 32770],                           // @context
  155 => [ 116, 164 ],                                   // type
  192 => 174,                                            // issuer
  186 => { 154 => 166, 206 => 178, 208 => 1234567890 },  // credentialStatus
  188 => { 154 => 172, 180 => h'753FF040 },              // credentialSubject
  194 => {                                               // proof
    154 => 108,                                          // type
    214 => 4,                                            // cryptosuite
    224 => 230                                           // verificationMethod
    228 => 176,                                          // proofPurpose
    210 => Uint8Array(65) [ ... ],                       // proofValue
  }
}

1.1.2 Employment Authorization

This section provides an example on how the technology in this specification can be utilized to secure the machine-readable zone on an employment authorization document that uses a machine-readable zone (MRZ) on the back of the card. We start off with an example employment authorization document:

Picture of the front of an employment authorization document issued by the state of Utopia which contains a picture of the individual that is the subject of the document along with their attributes, such as name, address, height, weight, eye color, and employment privileges.
Figure 3 The front of an employment authorization document issued by the state of Utopia.

The back of the employment authorization document contains a machine-readable zone (MRZ) containing information designed to be read through optical character recognition:

Picture of the back of a employment authorization document issued by the state of Utopia, containing usage rules as well as machine-readable zone data that encodes much of the information displayed on the front of the card.
Figure 4 A back of an employment authorization document issued by the state of Utopia.

The MRZ data contains information that is secured using the algorithms described in this specification. Namely, the QR Code on the front of the card contains a verifiable credential of the following form, which secures the information on the back of the card.

Example 3: Verifiable Credential expressed as a QR Code on the front of the card
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/citizenship/v2",
    "https://w3id.org/citizenship/utopia/v1"
  ],
  "type": [
    "VerifiableCredential",
    "OpticalBarcodeCredential"
  ],
  // the value below is defined as a URL in the 'utopia/v1' context above
  "issuer": "did:web:immigration.utopia.example",
  "credentialSubject": {
    "type": "MachineReadableZone",
  },
  "proof": {
    "type": "DataIntegrity",
    "cryptosuite": "ecdsa-xi-2023",
    // the value below is defined as a URL in the 'utopia/v1' context above
    "verificationMethod": "did:web:immigration.utopia.example#key-4"
    "proofPurpose": "assertionMethod",
    "proofValue": "z4peo48uwK2EF4Fta8P...HzQMDYJ34r9gL"
  }
}
Note: credentialStatus is optional

Readers might note that the credential above does not contain the optional credentialStatus property. Not every optical barcode credential issuer will have the requirement to have revocable optical barcode credentials.

The verifiable credential above is then compressed using [CBOR-LD] to the following output (in CBOR Diagnostic Notation):

Example 4: CBOR-LD compressed Verifiable Credential (120 bytes)
{
  1 => [ 32768, 32769, 32770],           // @context
  155 => [ 116, 176 ],                   // type
  208 => 194,                          // issuer
  204 => { 154 => 192 },                 // credentialSubject
  210 => {                               // proof
    154 => 108,                          // type
    226 => 4,                        // cryptosuite
    236 => 242                         // verificationMethod
    240 => 196,                          // proofPurpose
    210 => Uint8Array(65) [ ... ],       // proofValue
  }
}

1.1.3 Birth Certificate

This section provides an example on how the technology in this specification can be utilized to secure a birth certificate as a verifiable credential, which is then expressed as a QR Code on the printed paper document:

A picture of the front of a birth certificate containing information such as the newborn's name, parent's names, information about the hospital, attendees, and person responsible for the registration.
Figure 5 The front of a birth certificate issued by a hospital in the state of Utopia.

The QR Code encodes the following verifiable credential. The details of the encoding are available as separate tabs below:

Example 5: A verifiable credential expressing a short-form birth certificate
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/vital-records/v1rc1"
  ],
  "type": [
    "VerifiableCredential",
    "BirthCertificateCredential"
  ],
  "issuer": "https://hospital.example/issuer",
  "validFrom": "2023-09-30T11:30:00Z",
  "credentialSubject": {
    "type": "BirthCertificate",
    "certificationDate": "2023-09-30T13:44:52Z",
    "newborn": {
      "type": "Newborn",
      "name": "Tim Doe",
      "gender": "Male",
      "birthDate": "2023-10-05T14:29:00Z",
      "birthPlace": {
        "type": "PostalAddress",
        "streetAddress": "123 Hospital Rd",
        "addressLocality": "Utopia Town",
        "addressRegion": "Utopolis",
        "postalCode": "12345",
        "addressCountry": "Utopia"
      },
      "parent": [{
        "type": "Mother",
        "name": "Jane Doe",
        "namePriorToMarriage": "Jane Smith"
      }, {
        "type": "Father",
        "name": "John Doe"
      }]
    }
  }
}
application/vc+cborld

d9cb1d8201a60182782468747470733a2f2f7777772e77332e6f72672f6e732f63726564656e7469616c732f7632782468747470733a2f2f773369642e6f72672f766974616c2d7265636f7264732f7631726331189d82187618a4190130a3189c18a218cc74323032332d30392d33305431333a34343a35325a190104a618966754696d20446f65189c18ae18bc74323032332d31302d30355431343a32393a30305a18c4a6189c18b21901446655746f7069611901466b55746f70696120546f776e1901486855746f706f6c697319014a65313233343519014c6f31323320486f73706974616c20526418e2644d616c6519010b82a31896684a616e6520446f65189c18ac1901026a4a616e6520536d697468a21896684a6f686e20446f65189c18aa190134820277686f73706974616c2e6578616d706c652f697373756572190136a6189c186c1901501a6a57dab41901526f65636473612d726466632d3230313919015c19016219015e58417a0cc6305bbef515f9189690a835753af7681e27637f9998e691adf90a0928e39723e26e3d46dd5018bab53018cabc5c116006a15593b220928be34ef40f1706fb190160821904015823802403aa943808db3107ad5d75fae858927a8d60fc656a8d9c552b38b066004863e6ff1901401a651806b8

JSON-LD size: 1036 bytes
CBOR-LD size: 484 bytes
Compression : 53%

application/vc
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/vital-records/v1rc1"
  ],
  "type": [
    "VerifiableCredential",
    "BirthCertificateCredential"
  ],
  "issuer": "https://hospital.example/issuer",
  "validFrom": "2023-09-30T11:30:00Z",
  "credentialSubject": {
    "type": "BirthCertificate",
    "certificationDate": "2023-09-30T13:44:52Z",
    "newborn": {
      "type": "Newborn",
      "name": "Tim Doe",
      "gender": "Male",
      "birthDate": "2023-10-05T14:29:00Z",
      "birthPlace": {
        "type": "PostalAddress",
        "streetAddress": "123 Hospital Rd",
        "addressLocality": "Utopia Town",
        "addressRegion": "Utopolis",
        "postalCode": "12345",
        "addressCountry": "Utopia"
      },
      "parent": [
        {
          "type": "Mother",
          "name": "Jane Doe",
          "namePriorToMarriage": "Jane Smith"
        },
        {
          "type": "Father",
          "name": "John Doe"
        }
      ]
    }
  },
  "proof": {
    "type": "DataIntegrityProof",
    "created": "2026-07-15T19:08:36Z",
    "verificationMethod": "did:key:zDnaeu99ozL26MYFaqaT6iEEjfi9gFvw11NgcPwyJ2gbU1GpE",
    "cryptosuite": "ecdsa-rdfc-2019",
    "proofPurpose": "assertionMethod",
    "proofValue": "zFp9xXE3JE1Aka84rqNNr5RCGp53nfqrH75hDorpS8WM312CdxBKkV2bKH3GvuhefCN7pY925ittuRXYk
kurFtpi"
  }
}
            

CBOR-LD Diagnostic Mode
51997(
  [
    1,
    {
      1: [
        "https://www.w3.org/ns/credentials/v2",
        "https://w3id.org/vital-records/v1rc1"
      ],
      157: [
        118,
        164
      ],
      304: {
        156: 162,
        204: "2023-09-30T13:44:52Z",
        260: {
          150: "Tim Doe",
          156: 174,
          188: "2023-10-05T14:29:00Z",
          196: {
            156: 178,
            324: "Utopia",
            326: "Utopia Town",
            328: "Utopolis",
            330: "12345",
            332: "123 Hospital Rd"
          },
          226: "Male",
          267: [
            {
              150: "Jane Doe",
              156: 172,
              258: "Jane Smith"
            },
            {
              150: "John Doe",
              156: 170
            }
          ]
        }
      },
      308: [
        2,
        "hospital.example/issuer"
      ],
      310: {
        156: 108,
        336: 1784142516,
        338: "ecdsa-rdfc-2019",
        348: 354,
        350: h'7a0cc6305bbef515f9189690a835753af7681e27637f9998e691adf90a0928e39723e26e3d46dd5018bab
53018cabc5c116006a15593b220928be34ef40f1706fb',
        352: [
          1025,
          h'802403aa943808db3107ad5d75fae858927a8d60fc656a8d9c552b38b066004863e6ff'
        ]
      },
      320: 1696073400
    }
  ])}
            
image/png

Verifiable Credential QR Code
QR Code version: 15
Error correction: Low

QR Code Content (text)
VC1-R0OR*W3H90Q80L8FA9DIWENPEJ/5S4F03F53F7*5$KE$:5CPEXPC  C1$CBWEAECCPEI.EL8FA9DIWENPEJ/553FPED7*5$K
E006-EDAECOX5Z C04EKVC006DB6DOC1534KG$-EOXKY60$RK0XJ6MK5%PNF6QF63W5CA79L6/SAJL6:Q66G7KG6B73KQ0*43$2D
YEDP34W3E053I53W531VE8466L6$963W5HX6-963G7PA7646OHBW%O053M53B735T86 A/3EMEDB73R+86 A/3EMED-3454EF-DD
70O8DHWES9EXVDZOEF70UZCQF60R6B73$T9*96%K6379WQE-EDAEC*34JTC-RS9Z9TVDB73LK1$RKT0J6I91/DP34W3E053G53B7
3XD06I91/D+34J$DAWE6MKT0JKI949DP34W3E053E53B73WS61E059DWQE-EDAEC.%5$9FQ$DTVDW:5ZQE%$E4JE+60+:K0XJ/TD
L70CF3Z4BPYMN70W3EJPCHQEOX57VC9OCNF61A6B73.SB*70B73W-BMC8VS8:Y2RKO%2PERND.I1YJCWIQS5.XBV+GSG3X%IMKD0
ZGB20V09KBU4:M9PCS:LE531QP.GKOX9FZ1U:F3WI26J*L1MGF8 FB7319CE73T70/L4*O4IPLY37/VRU/0U BHWV*8B8MFXBC. 
CR+HNYAM77C+C 6959TB73U485ZCA%0
            

JSON-LD Diagnostic Mode
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/vital-records/v1rc1"
  ],
  "type": [
    "VerifiableCredential",
    "BirthCertificateCredential"
  ],
  "issuer": "https://hospital.example/issuer",
  "validFrom": "2023-09-30T11:30:00Z",
  "credentialSubject": {
    "type": "BirthCertificate",
    "certificationDate": "2023-09-30T13:44:52Z",
    "newborn": {
      "type": "Newborn",
      "name": "Tim Doe",
      "gender": "Male",
      "birthDate": "2023-10-05T14:29:00Z",
      "birthPlace": {
        "type": "PostalAddress",
        "streetAddress": "123 Hospital Rd",
        "addressLocality": "Utopia Town",
        "addressRegion": "Utopolis",
        "postalCode": "12345",
        "addressCountry": "Utopia"
      },
      "parent": [
        {
          "type": "Mother",
          "name": "Jane Doe",
          "namePriorToMarriage": "Jane Smith"
        },
        {
          "type": "Father",
          "name": "John Doe"
        }
      ]
    }
  },
  "proof": {
    "type": "DataIntegrityProof",
    "created": "2026-07-15T19:08:36Z",
    "verificationMethod": "did:key:zDnaeu99ozL26MYFaqaT6iEEjfi9gFvw11NgcPwyJ2gbU1GpE",
    "cryptosuite": "ecdsa-rdfc-2019",
    "proofPurpose": "assertionMethod",
    "proofValue": "z2NEKCQcfdiaQWaj9QpGJhv8wvs7spCTsbe8FMSLqyAV2nzTSQ6JaGoDkxFyYoeaYMCPqVndY5Xn9sDc3
LkhPKg5p"
  }
}}
            

1.2 Design Goals

The following are the design goals of the technology in this specification:

1.3 Terminology

Terminology used throughout this document is defined in the Terminology section of the Verifiable Credentials Data Model v2.0 specification as well as the Verifiable Credential Data Integrity 1.0 specification.

Unicode code point order
This refers to determining the order of two Unicode strings (A and B), using Unicode Codepoint Collation, as defined in [XPATH-FUNCTIONS], which defines a total ordering of strings comparing code points. Note that for UTF-8 encoded strings, comparing the byte sequences gives the same result as code point order.

1.4 Conformance

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, RECOMMENDED, and REQUIRED 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 document 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 document. 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.

2. Data Model

The following sections outline the data model that is used by this specification to express verifiable credentials that secure optically printed information such as barcodes and machine-readable zones on travel documents.

2.1 OpticalBarcodeCredential

An OpticalBarcodeCredential is used to secure the contents of an optical barcode in a way that provides 1. authorship information, 2. tamper resistance, and 3. optionally, revocation and suspension status. In other words, the credential can tell you who issued the optical barcode, if the optical barcode has been tampered with since it was first issued, and whether or not the issuer of the optical barcode still warrants that the document is still valid or not. These features provide significant anti-fraud protections for physical documents.

The type of the credentialSubject of an OpticalBarcodeCredential identifies the kind of machine-readable data on the physical document that is secured by the verifiable credential, in addition to the information expressed in the verifiable credential itself. This specification defines the general type MachineReadableInformation, which serves as the superclass for every credentialSubject type used with an OpticalBarcodeCredential. The main portion of this specification defines one concrete subclass: MachineReadableZone (see Section 2.1.1 MachineReadableZone), which signifies that the verifiable credential secures the machine-readable zone on the physical document. Two further subclasses are defined in the appendices: AamvaDriversLicenseScannableInformation (see Appendix A. AAMVA Driver License and Identification Documents, which is normative) and IsoDrivingLicenceMachineReadableInformation (see Appendix B. ISO-Compliant Driving Licences, which is informative). Other specifications MAY define additional credentialSubject types that indicate the credential protects other sorts of machine-readable data, such as PDF417 barcodes on birth certificates or education certificates.

Every credentialSubject type used with an OpticalBarcodeCredential, whether defined by this specification or by another, MUST be defined as a subclass of MachineReadableInformation. The value MachineReadableInformation MAY be included in the credentialSubject type array alongside the more specific subclass value; processors that do not recognize a specific subclass can use the superclass value to determine that the credentialSubject describes machine-readable data secured by the verifiable credential.

A new credentialSubject type, whether defined by this specification or by another, MUST define all of the following in order to be usable with the algorithms in Section 3. Algorithms:

An example of how such an additional type can be defined to secure a region-specific barcode data model is available in Appendix A. AAMVA Driver License and Identification Documents, which normatively defines how to augment the PDF417 barcode on AAMVA-compliant driver's licenses and identification cards with a Verifiable Credential Barcode.

When the machine-readable data secured by an OpticalBarcodeCredential is composed of discrete components (such as the individual fields in a PDF417 barcode), and only a subset of those components is digitally signed, the credentialSubject expresses which components are protected using the protectedComponentIndex property. The value of protectedComponentIndex is a multibase-base64url encoded bitstring. Each bit in position i of the bitstring corresponds to the component at index i of the deterministic list of components defined for the associated credentialSubject type. If the bit in position i is 1, the component in position i of the deterministic list of components is protected by the digital signature; if the bit is 0, the component is not protected. Any trailing padding bits in the bitstring that do not correspond to a component MUST be set to 0. For more information on how protectedComponentIndex is used when generating and verifying digital signatures, see Section 3.2.4.4 Create opticalDataBytes.

2.1.1 MachineReadableZone

A credentialSubject of type MachineReadableZone signifies that the verifiable credential secures the machine-readable zone (MRZ) [ICAO9303-3] on the physical document. MachineReadableZone is a subclass of MachineReadableInformation. All of the lines of the machine-readable zone are secured, so the protectedComponentIndex property is not needed with this type.

It is REQUIRED that implementers re-encode CBOR-LD encoded MachineReadableZone credentials as base45-multibase with the string 'VC1-' prepended before encoding them in a QR code.

2.2 TerseBitstringStatusListEntry

A TerseBitstringStatusListEntry is a compact representation of a BitstringStatusListEntry as defined in the Bitstring Status List v1.0 specification.

An object of type TerseBitstringStatusListEntry MUST have two additional properties:

To process a TerseBitstringStatusListEntry, apply the algorithm in Section 3.2.3.1 TerseBitstringStatusListEntry to BitstringStatusListEntry to convert it to a BitstringStatusListEntry, then process it as in Bitstring Status List v1.0.

Implementers need to set a value listLength for the length of an individual status list. This then yields a number of status lists listCount = 2^32 / listLength for a 32-bit terseStatusListIndex. listLength is needed to convert from a TerseBitstringStatusListEntry to a BitstringStatusListEntry. Noting that some values of listLength will harm the privacy-preserving properties of these status lists, implementations MUST use listLength = 2^26 and listCount = 2^6.

2.3 Encoding to and from barcodes

While the credentials in this specification use CBOR-LD to efficiently encode verifiable credentials in a binary format, binary data is often inefficient or incompatible to turn into standard barcode image formats directly. To that end, character encoding requirements for implementations are provided on a per-type basis, and will typically vary based on the target barcode format.

Each credentialSubject type is expected to specify how CBOR-LD encoded credentials of that type are character-encoded before being placed in a barcode. The character encoding requirements for MachineReadableZone are provided in Section 2.1.1 MachineReadableZone; requirements for other types are provided in the specifications or appendices that define them (e.g., Appendix A. AAMVA Driver License and Identification Documents and Appendix B. ISO-Compliant Driving Licences).

3. Algorithms

The following section describes algorithms for adding and verifying digital proofs that protect optical information, such as barcodes and machine-readable zones, on physical media, such as driver's licenses and travel documents.

3.1 General Algorithms

This section contains algorithms that are general to encoding and decoding verifiable credentials.

3.1.1 Encode VC to QR Code

The following algorithm specifies how to encode a verifiable credential into a text string that can be expressed in a QR Code. Required inputs are a verifiable credential (map inputDocument), and a set of options (map options). The output is an encoded verifiable credential (string) or an error. Whenever this algorithm encodes strings, it MUST use UTF-8 encoding.

  1. Let typeTable be the value of options.typeTable.
  2. Let registryEntryId be the value of options.registryEntryId.
  3. Let cborldDocument be the result of the JSON-LD to CBOR-LD Encoding Algorithm, passing inputDocument, typeTable, and registryEntryId as inputs. If an encoding error occurs, an error MUST be raised.
  4. Let base45Value be the result of the Base Encoding algorithm, passing cborldDocument as bytes, the integer 45 as targetBase, and 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./: as the baseAlphabet.
  5. Let qrCodeText be the result of concatenating the following values: VC1-, R (the Multibase prefix for base45), and base45Value.
  6. Return qrCodeText as the encoded verifiable credential, which can then be provided to any QR Code library as text to be encoded as a QR Code image.

3.1.2 Decode QR Code to VC

The following algorithm specifies how to decode a verifiable credential that has been encoded into a QR Code. Required inputs are a text string (string inputDocument), and a set of options (map options). The output is a verifiable credential (map) or an error. Whenever this algorithm encodes strings, it MUST use UTF-8 encoding.

  1. Ensure that the inputDocument starts with the text VC1-R. If it does not an error MUST be raised.
  2. Let base45Value be inputDocument with the first five characters (VC1-R) removed.
  3. Let cborldDocument be the result of the Base Decoding algorithm, passing base45Value as sourceEncoding, the integer 45 as sourceBase, and 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./: as the baseAlphabet.
  4. Let jsonldDocument be the result of CBOR-LD to JSON-LD Decoding Algorithm, passing cborldDocument as the input. If a decoding error occurs, an error MUST be raised.
  5. Return jsonldDocument as the decoded verifiable credential.

3.2 OpticalBarcodeCredential Algorithms

This section contains algorithms that are specific to encoding and decoding verifiable credentials that have a type of OpticalBarcodeCredential, which typically appears in the use case where existing machine-readable information on a document is augmented with a verifiable credential.

3.2.1 Encode OpticalBarcodeCredential

  1. Set opticalData to the data in the optical barcode to be secured.
  2. Set issuerUrl to the URL the issuer wishes to use for credential verification.
  3. Set unsignedCredential to an OpticalBarcodeCredential with unsignedCredential.issuer set to issuerUrl.
  4. If credential status is required:
    1. Set statusListEntry to the BitstringStatusListEntry (as defined in the Bitstring Status List v1.0 specification) that the issuer wishes to add to the OpticalBarcodeCredential.
    2. Set unsignedCredential.credentialStatus to the result of applying the algorithm in Section 3.2.3.2 BitstringStatusListEntry to TerseBitstringStatusListEntry to statusListEntry.
  5. Set signedCredential to the result of using the algorithm in 3.2.4.1 Add Proof (ecdsa-xi-2023) to sign opticalData and unsignedCredential.
  6. Encode signedCredential using CBOR-LD [CBOR-LD] and add it to the designated area of the opticalData in accordance with the processing rules for the desired value of credentialSubject.type and the use case.

3.2.2 Decode OpticalBarcodeCredential

  1. Set opticalData to the machine-readable data (e.g., the PDF417 or MRZ data) scanned from the physical document.
  2. Set vcbPayload to the verifiable credential payload extracted from the designated area of opticalData.
  3. Set cborldBytes to the result of decoding vcbPayload from the character encoding associated with the credential type and barcode format (see Section 2.3 Encoding to and from barcodes), removing any multibase header if one is present.
  4. Set credential to the OpticalBarcodeCredential that results from applying CBOR-LD decompression [CBOR-LD] to cborldBytes, if the payload is CBOR-LD compressed; otherwise, set credential to the OpticalBarcodeCredential expressed by cborldBytes.
  5. Set verificationResult to the result of applying the algorithm in Section 3.2.4.2 Verify Proof (ecdsa-xi-2023) to credential and opticalData.
  6. Set statusResult to null. If credential.credentialStatus is present:
    1. Set statusListEntry to the result of applying the algorithm in Section 3.2.3.1 TerseBitstringStatusListEntry to BitstringStatusListEntry to credential.
    2. Set statusResult to the result of applying the algorithm in Bitstring Status List v1.0: Validate Algorithm to statusListEntry.
  7. Return (verificationResult, statusResult).

3.2.3 Convert Status List Entries

The algorithms in this section are used to convert between a TerseBitstringStatusListEntry and a BitstringStatusListEntry. The algorithm in Section 3.2.3.2 BitstringStatusListEntry to TerseBitstringStatusListEntry is used when encoding an OpticalBarcodeCredential, to compress a BitstringStatusListEntry into a TerseBitstringStatusListEntry before the credential is signed. The algorithm in Section 3.2.3.1 TerseBitstringStatusListEntry to BitstringStatusListEntry performs the inverse conversion and is used after verification has been performed on the verifiable credential, during the validation process.

3.2.3.1 TerseBitstringStatusListEntry to BitstringStatusListEntry

After verifiable credential verification has been performed, the algorithm takes an OpticalBarcodeCredential verifiable credential (struct vc), an integer listLength containing the number of entries in the BitstringStatusListCredential associated with vc, and a string statusPurpose (e.g., 'revocation', 'suspension'...) as input and returns a 'BitstringStatusListEntry' object.

  1. Set result to be an empty map.
  2. Set listIndex to vc.credentialStatus.terseStatusListIndex/listLength rounded down to the next lowest integer (i.e., apply the floor() operation).
  3. Set statusListIndex to vc.credentialStatus.terseStatusListIndex % listLength.
  4. Set result.statusListCredential to the concatenation of the following values: vc.credentialStatus.terseStatusListBaseUrl, '/', statusPurpose, '/', listIndex.
  5. Set result.type to 'BitstringStatusListEntry'.
  6. Set result.statusListIndex to statusListIndex.
  7. Set result.statusPurpose to statusPurpose.
  8. Return result.

result can be used as input to the validation algorithm in the Bitstring Status List v1.0 specification.

3.2.3.2 BitstringStatusListEntry to TerseBitstringStatusListEntry

The algorithm takes a BitstringStatusListEntry (struct statusListEntry), whose statusListCredential value is expected to be a URL of the form terseStatusListBaseUrl, '/', statusPurpose, '/', listIndex, and an integer listLength containing the number of entries in each BitstringStatusListCredential published by the issuer as input, and returns a 'TerseBitstringStatusListEntry' object.

  1. Set result to be an empty map.
  2. Set listIndex to the integer representation of the final path segment of statusListEntry.statusListCredential.
  3. Set terseStatusListBaseUrl to statusListEntry.statusListCredential with the final two path segments (i.e., '/', statusPurpose, '/', listIndex) removed.
  4. Set result.type to 'TerseBitstringStatusListEntry'.
  5. Set result.terseStatusListBaseUrl to terseStatusListBaseUrl.
  6. Set result.terseStatusListIndex to listIndex * listLength + the integer representation of statusListEntry.statusListIndex.
  7. Return result.
Note: The status purpose is not carried in the terse entry

A TerseBitstringStatusListEntry does not express the statusPurpose of the original BitstringStatusListEntry. The statusPurpose is instead supplied by the verifier as an input to the algorithm in Section 3.2.3.1 TerseBitstringStatusListEntry to BitstringStatusListEntry, which reconstructs the BitstringStatusListEntry during validation.

Note: Status lists are optional

Implementers are advised that not all issuers will publish status list information for their verifiable credentials. Some issuers might require authorization before allowing a verifier to access a status list credential.

3.2.4 ecdsa-xi-2023

The ecdsa-xi-2023 cryptosuite is effectively the ecdsa-rdfc-2019 algorithm [VC-DI-ECDSA] with an added step that takes some "extra information" (xi) as input, such as the original optical barcode data, and includes that data in the information that is protected by the digital signature. The algorithms in this section detail how such a signature is created and verified.

3.2.4.1 Add Proof (ecdsa-xi-2023)

To generate a proof, the algorithm in Section 4.1: Add Proof in the Data Integrity [VC-DATA-INTEGRITY] specification MUST be executed. For that algorithm, the cryptographic suite specific transformation algorithm is defined in the Transformation (ecdsa-rdfc-2019) section of the Data Integrity ECDSA Cryptosuites v1.0, the hashing algorithm is defined in Section 3.2.4.3 Hashing (ecdsa-xi-2023), and the proof serialization algorithm is defined in the Proof Serialization (ecdsa-rdfc-2019) section of the Data Integrity ECDSA Cryptosuites v1.0.

3.2.4.2 Verify Proof (ecdsa-xi-2023)

To verify a proof, the algorithm in Section 4.2: Verify Proof in the Data Integrity [VC-DATA-INTEGRITY] specification MUST be executed. For that algorithm, the cryptographic suite specific transformation algorithm is defined in the Transformation (ecdsa-rdfc-2019) section of the Data Integrity ECDSA Cryptosuites v1.0, the hashing algorithm is defined in Section 3.2.4.3 Hashing (ecdsa-xi-2023), and the proof verification algorithm is defined in the Proof Verification (ecdsa-rdfc-2019) section of the Data Integrity ECDSA Cryptosuites v1.0.

3.2.4.3 Hashing (ecdsa-xi-2023)

The hashing algorithm is what is defined in the Hashing (ecdsa-rdfc-2019) section of the Data Integrity ECDSA Cryptosuites v1.0 specification with the addition of the hashing of the optical data, as described below. It is presumed that the implementation makes the machine-readable optical data (PDF417 or MRZ data) available to this hashing algorithm.

The required inputs to this algorithm are a transformed data document (transformedDocument), a canonical proof configuration (canonicalProofConfig), and the optical data (opticalDataBytes). A single hash data value represented as series of bytes is produced as output.

The hashing algorithm is what is defined in the Hashing (ecdsa-rdfc-2019) section of the Data Integrity ECDSA Cryptosuites v1.0 with step 3 replaced with the following two steps:

  1. Let opticalDataHash be the result of applying the same hash algorithm that was applied to hashData to the opticalDataBytes value.
  2. Let hashData be the result of joining proofConfigHash (the first hash), transformedDocumentHash (the second hash), and opticalDataHash (the third hash).
3.2.4.4 Create opticalDataBytes

The algorithm in this section produces the optical data (opticalDataBytes) over which a digital signature is generated or verified. The algorithm is generic to any sort of machine-readable optical data: the type of the credentialSubject defines how the protected components of the optical data are extracted (see the type-specific component extraction sections below), and this algorithm sorts those components into a deterministic list before canonicalizing and hashing them.

The required inputs to this algorithm are the machine-readable optical data (opticalData) and the credential subject (credentialSubject). A single value representing the hashed canonical form of the protected optical data is produced as output.

  1. Set dataToCanonicalize to the result of extracting the protected components of opticalData as an array of strings, according to the component extraction rules associated with the type of credentialSubject, using credentialSubject.protectedComponentIndex if it is defined for that type. The component extraction rules for MachineReadableZone are given in Section Component extraction: MachineReadableZone; the rules for other types are given in the specifications or appendices that define them (e.g., Appendix A.2 Component Extraction for the type defined in Appendix A. AAMVA Driver License and Identification Documents, and Appendix B.2 Component Extraction for the type described in Appendix B. ISO-Compliant Driving Licences).
  2. Set canonicalizedData to the result of sorting dataToCanonicalize into a deterministic list, using the ordering rules associated with the type of credentialSubject, and then applying a join operation to create a single string from the array. If the type of credentialSubject does not define ordering rules, sort dataToCanonicalize in Unicode code point order.
  3. Hash canonicalizedData and return the result.
Component extraction: MachineReadableZone

For a credentialSubject of type MachineReadableZone, opticalData is the data in the machine-readable zone, and the protected components are extracted as follows. The ordering rules for this type are the order in which the lines appear on the credential.

  1. Set dataToCanonicalize to an empty array.
  2. For each line in the Machine Readable Zone on the credential:
    1. Set mrzLine to a string containing the data in that line.
    2. Append a newline character to the end of mrzLine and append mrzLine to dataToCanonicalize.
  3. Return dataToCanonicalize.
3.2.4.5 Proof Configuration (ecdsa-xi-2023)

The proof configuration algorithm is what is defined in the Proof Configuration (ecdsa-rdfc-2019) section of the Data Integrity ECDSA Cryptosuites v1.0 with step 4 replaced with the following step:

  1. If options.type is not set to DataIntegrityProof and proofConfig.cryptosuite is not set to ecdsa-xi-2023, an INVALID_PROOF_CONFIGURATION error MUST be raised.

4. Security Considerations

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 as well as the specific security advice provided in the Security Considerations section of the ECDSA Cryptosuites specification.

In the following sections, we review these important points and direct the reader to additional information.

4.1 Optical Data Duplication

One attack vector against OpticalBarcodeCredentials involves duplicating an optical barcode containing a digital signature for use on a fraudulent document. While a duplicated barcode will pass signature validation like the original, this attack is mitigated by the document verifier checking the following three things: the signed data matches the data visible on the document, the signed data matches the physical attributes of the user, and the visible data matches the physical attributes of the user. When these three are all equivalent, the only way the OpticalBarcodeCredential could be a duplicate is if the fraudulent document creator had access to a real OpticalBarcodeCredential where the signed physical attributes fully overlapped with those of the user of the fraudulent document. The low likelihood of an undetected stolen OpticalBarcodeCredential existing that completely matches the appearance of an arbitrary person makes this attack unlikely to succeed.

4.2 Partially Signed Optical Data

It is possible that in some cases the digital signature cannot be created over the entirety of the existing optical data. For example, consider a case where a serial number is injected by a physical credential manufacturer such that it is not known to the issuer at signature time. In this case, the verifier will assume that any data not digitally signed could have been changed in the optical barcode without impacting the OpticalBarcodeCredential's ability to successfully validate.

When checking that data from the optical barcode matches the data visible on the document as well as the characteristics of the document holder, implementers are advised to only use the fields that are digitally signed. Verifiers are advised to only use fields protected by the digital signature, no matter how commonly the other fields are used for fraud detection on unsigned documents. For example, if eye color and hair color are protected by the signature, but the holder's portrait is not, verifiers are advised to emphasize the eye color and hair color when attempting to detect fraud over the portrait.

Implementers of software used by verifiers are advised to only display card data that has been secured via digital signature during the verification process. Displaying unsigned data, which could have been tampered with, could interfere with fraud detection.

4.3 Safe Verification

Verifiers are advised to always use trusted programs and interfaces to check the validity of the OpticalBarcodeCredential. Use of untrusted software to verify a document could result in a fraudulent credential being accepted, or a genuine credential being stolen.

5. Privacy 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 as well as the specific security advice provided in the Security Considerations section of the ECDSA Cryptosuites specification.

The following section describes privacy considerations that developers implementing this specification should be aware of in order to avoid violating privacy assumptions.

Issue 1
Add more privacy considerations including at least the following:
  • Barcodes can be read at a distance; therefore information that is very sensitive should not be encoded into a barcode and might be better transmitted via NFC or an encrypted online communication channel.

A. AAMVA Driver License and Identification Documents

This appendix defines AamvaDriversLicenseScannableInformation, a credentialSubject type, defined as a subclass of MachineReadableInformation, that is used to secure the contents of the PDF417 barcode on driver's licenses and identification cards issued in accordance with the AAMVA DL/ID Card Design Standard [aamva-dl-id-card-design-standard]. This type satisfies the requirements for new credentialSubject types set out in Section 2.1 OpticalBarcodeCredential, and this appendix also serves as an example of how such a type can be defined for the documents issued by a particular country or region; other specifications are encouraged to define similar types for other classes of documents.

A.1 AamvaDriversLicenseScannableInformation

A credentialSubject of type AamvaDriversLicenseScannableInformation signifies that the verifiable credential secures the contents of the PDF417 barcode on an AAMVA-compliant driver's license or identification card [aamva-dl-id-card-design-standard].

An AamvaDriversLicenseScannableInformation object has a REQUIRED protectedComponentIndex property that contains information about which fields in the PDF417 are digitally signed. protectedComponentIndex MUST be a three byte/24 bit value that is multibase-base64url encoded for a total of 5 characters in the JSON-LD credential. There are 22 mandatory fields in an AAMVA-compliant driver's license PDF417 [aamva-dl-id-card-design-standard], and the first 22 bits of the protectedComponentIndex value correspond to these fields. Each AAMVA mandatory field begins with a three character element ID (e.g., DBA for document expiration date). The deterministic list of components associated with this type is the list of these 22 element IDs sorted according to Unicode code point order (i.e., ['DAC', 'DAD' ... 'DDG']). If a bit in position i of protectedComponentIndex is 1, the AAMVA mandatory field in position i of the sorted element IDs is protected by the digital signature. The last two bits in protectedComponentIndex are padding bits and MUST be 0. For more information, see Section 3.2.4.4 Create opticalDataBytes.

It is RECOMMENDED that implementers character-encode CBOR-LD encoded AamvaDriversLicenseScannableInformation credentials as base64url before encoding them in a PDF417. A multibase header MAY be prepended to the base-encoded VCB data. PDF417 field header specifications are expected to indicate whether a multibase header is present or absent.

Example 6: An OpticalBarcodeCredential with credentialSubject of type AamvaDriversLicenseScannableInformation
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/vc-barcodes/v1"
  ],
  "type": [
    "VerifiableCredential",
    "OpticalBarcodeCredential"
  ],
  "issuer": "did:web:dmv.utopia.example",
  "credentialStatus": {
    "type": "TerseBitstringStatusListEntry",
    "terseStatusListBaseUrl": "dmv.utopia.gov/statuses/12345/status-lists"
    "terseStatusListIndex": 123567890
  },
  "credentialSubject": {
    "type": "AamvaDriversLicenseScannableInformation",
    "protectedComponentIndex": "uP_BA"
  }
}

A.2 Component Extraction

For a credentialSubject of type AamvaDriversLicenseScannableInformation, opticalData is the data in the PDF417 barcode, and the protected components are extracted as follows. The ordering rules for this type are the default Unicode code point order.

  1. Set dataToCanonicalize to an empty array.
  2. Set bitfieldDecoded to be first 22 bits of the length 24 bitstring resulting from decoding credentialSubject.protectedComponentIndex from multibase-base64url to binary.
  3. Set fieldsAlphabetized to be the deterministic list of components for this type, i.e., an array containing the 22 AAMVA mandatory PDF417 Element IDs [aamva-dl-id-card-design-standard] sorted in Unicode code point order (i.e., ['DAC', 'DAD' ... 'DDG']).
  4. For each bit with value 1 in bitfieldDecoded:
    1. Set the string fieldName to fieldsAlphabetized[i], where i is the index of the bit in bitfieldDecoded.
    2. Set the string fieldData to the data that will be in the PDF417 associated with that field name.
    3. Concatenate fieldData to the end of fieldName, concatenate a newline character (\n, U+000A) to the end, and append the result to dataToCanonicalize.
  5. Return dataToCanonicalize.

B. ISO-Compliant Driving Licences

This section is non-normative.

This appendix describes IsoDrivingLicenceMachineReadableInformation, a credentialSubject type, defined as a subclass of MachineReadableInformation, that can be used to secure the machine-readable data on an ISO-compliant driving licence (IDL) [ISO18013-2]. It illustrates how a credentialSubject type satisfying the requirements in Section 2.1 OpticalBarcodeCredential could be defined for IDLs, and is expected to be refined by a future revision of this specification, or by another specification, before use.

B.1 IsoDrivingLicenceMachineReadableInformation

A credentialSubject of type IsoDrivingLicenceMachineReadableInformation signifies that the verifiable credential secures the compact-encoded machine-readable data, as defined in [ISO18013-2], on an ISO-compliant driving licence (IDL), such as the contents of a PDF417 barcode on the licence. The machine-readable IDL data is organized into data groups (DG1 through DG11) as defined by the logical data structure in [ISO18013-2]; these data groups are the components of the optical data for the purposes of this specification. IsoDrivingLicenceMachineReadableInformation is a subclass of MachineReadableInformation.

An IsoDrivingLicenceMachineReadableInformation object has a required protectedComponentIndex property that contains information about which data groups are digitally signed. protectedComponentIndex is a two byte/16 bit value that is multibase-base64url encoded for a total of 4 characters in the JSON-LD credential. The deterministic list of components associated with this type is the list of data groups defined in [ISO18013-2], sorted in ascending order of data group number (i.e., ['DG1', 'DG2' ... 'DG11']), and the first 11 bits of the protectedComponentIndex value correspond to these data groups. If a bit in position i of protectedComponentIndex is 1, the data group in position i of the deterministic list of components is protected by the digital signature. The remaining bits in protectedComponentIndex are padding bits and are set to 0. For more information, see Section 3.2.4.4 Create opticalDataBytes.

Implementers are expected to character-encode CBOR-LD encoded IsoDrivingLicenceMachineReadableInformation credentials as base64url before encoding them in a PDF417. A multibase header can be prepended to the base-encoded VCB data. The encoded VCB is expected to be placed in Data Group 11, for optional and jurisdiction-specific data. If the VCB is placed into one of the 11 Data Groups, the corresponding element of protectedComponentIndex is set to 0.

B.2 Component Extraction

For a credentialSubject of type IsoDrivingLicenceMachineReadableInformation, opticalData is the compact-encoded machine-readable data [ISO18013-2] on the licence, and the protected components are extracted as follows. The ordering rules for this type are ascending order of data group number.

  1. Set dataToCanonicalize to an empty array.
  2. Set bitfieldDecoded to be the first 11 bits of the length 16 bitstring resulting from decoding credentialSubject.protectedComponentIndex from multibase-base64url to binary.
  3. Set dataGroupsOrdered to be the deterministic list of components for this type, i.e., an array containing the data group identifiers defined in [ISO18013-2] sorted in ascending order of data group number (i.e., ['DG1', 'DG2' ... 'DG11']).
  4. For each bit with value 1 in bitfieldDecoded:
    1. Set the string dataGroupName to dataGroupsOrdered[i], where i is the index of the bit in bitfieldDecoded.
    2. Set the string dataGroupData to a base64url encoding of the contents of the data group identified by dataGroupName in opticalData, as delimited by the data group delimiter character.
    3. Concatenate dataGroupData to the end of dataGroupName, concatenate a newline character (\n, U+000A) to the end, and append the result to dataToCanonicalize.
  5. Return dataToCanonicalize.

C. Test Vectors

This section is non-normative.

This section contains examples of Verifiable Credential Barcodes as well as step-by-step processes for how they are generated and how they are verified.

In this section we will analyze two running examples: a VCB securing the MRZ of a Utopia Employment Authorization Document, and a VCB securing the PDF417 of a Utopia Driver's License.

C.1 Creating VCBs

C.1.1 Utopia Driver's License

We start with the data that will be signed by the VCB (i.e., mandatory AAMVA fields from a PDF417):

Example 7: Fields from a PDF417 that might appear on a Utopia Driver's License
DACJOHN
DADNONE
DAG123 MAIN ST
DAIANYVILLE
DAJUTO
DAKF87P20000
DAQF987654321
DAU069 IN
DAYBRO
DBA04192030
DBB04191988
DBC1
DBD01012024
DCAC
DCBNONE
DCDNONE
DCFUTODOCDISCRIM
DCGUTO
DCSSMITH
DDEN
DDFN
DDGN
C.1.1.1 Creating opticalDataBytes

Assume for simplicity that the only data in the PDF417 that you want to sign is first name (DAC), last name (DCS), and license number (DAQ). The bitstring value for use in protectedComponentIndex is then 100000100000000000100000, and the value of protectedComponentIndex is "uggAg". Applying 3.2.4.4 Create opticalDataBytes, we get

Example 8: Data from the canonicalization of a Utopia Driver's License
canonicalizedData = 'DACJOHN\nDAQF987654321\nDCSSMITH\n'
opticalDataBytes:
  [188,  38, 200, 146, 227, 213,  90, 250,
  50,  18, 126, 254,  47, 177,  91,  23,
  64, 129, 104, 223, 136,  81, 116,  67,
  136, 125, 137, 165, 117,  63, 152, 207]

We can now use this hash value with 3.2.4.3 Hashing (ecdsa-xi-2023) to sign the VC. Executing 3.2.1 Encode OpticalBarcodeCredential with a BitstringStatusListCredential, we get the following JSON-LD VC:

C.1.1.2 Example VC
Example 9: A JSON-LD VC for a Utopia Driver's License VCB
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/vc-barcodes/v1",
    "https://w3id.org/utopia/v2"
  ],
  "type": [
    "VerifiableCredential",
    "OpticalBarcodeCredential"
  ],
  "credentialSubject": {
    "type": "AamvaDriversLicenseScannableInformation",
    "protectedComponentIndex": "uggAg"
  },
  "issuer": "did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj",
  "credentialStatus": {
    "type": "TerseBitstringStatusListEntry",
    "terseStatusListBaseUrl": "https://sandbox.platform.veres.dev/statuses/z19rJ4oGrbFCqf3cNTVDHSbNd/status-lists",
    "terseStatusListIndex": 3851559041
  },
  "proof": {
    "type": "DataIntegrityProof",
    "verificationMethod": "did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj#zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj",
    "cryptosuite": "ecdsa-xi-2023",
    "proofPurpose": "assertionMethod",
    "proofValue": "z4g6G3dAZhhtPxPWgFvkiRv7krtCaeJxjokvL46fchAFCXEY3FeX2vn46MDgBaw779g1E1jswZJxxreZDCrtHg2qH"
  }
}
C.1.1.3 CBOR-LD Compression and Encoding

We can now apply CBOR-LD compression to this VC. Here, we use the newest version of CBOR-LD; however, at the end of the section, we provide VCBs encoded using older versions of CBOR-LD for interoperability testing with CBOR-LD implementations that are not up to date.

For this specification, we have reserved the CBOR-LD registry entry with value 100 (i.e., these payloads will begin with tag 0x0664). The parameters to encode using CBOR-LD, which can be found in the registry in the CBOR-LD specification, are then as follows:

Example 10: CBOR-LD encoding parameters
registryEntryId: 100
typeTable:
{
  "context":
    {
      "https://www.w3.org/ns/credentials/v2": 32768,
      "https://w3id.org/vc-barcodes/v1": 32769,
      "https://w3id.org/utopia/v2": 32770
    },

  "https://w3id.org/security#cryptosuiteString":
    {
      "ecdsa-rdfc-2019": 1,
      "ecdsa-sd-2023": 2,
      "eddsa-rdfc-2022": 3,
      "ecdsa-xi-2023": 4
    }
}

The term-to-ID mapping that should result from processing the contexts and assigning integer values to context terms is as follows:

Example 11: The term-to-ID map created by CBOR-LD when compressing a Utopia DL
Map(97) {
  '@context' => 0,
  '@type' => 2,
  '@id' => 4,
  '@value' => 6,
  '@direction' => 8,
  '@graph' => 10,
  '@included' => 12,
  '@index' => 14,
  '@json' => 16,
  '@language' => 18,
  '@list' => 20,
  '@nest' => 22,
  '@reverse' => 24,
  '@base' => 26,
  '@container' => 28,
  '@default' => 30,
  '@embed' => 32,
  '@explicit' => 34,
  '@none' => 36,
  '@omitDefault' => 38,
  '@prefix' => 40,
  '@preserve' => 42,
  '@protected' => 44,
  '@requireAll' => 46,
  '@set' => 48,
  '@version' => 50,
  '@vocab' => 52,
  '...' => 100,
  'BitstringStatusList' => 102,
  'BitstringStatusListCredential' => 104,
  'BitstringStatusListEntry' => 106,
  'DataIntegrityProof' => 108,
  'EnvelopedVerifiableCredential' => 110,
  'EnvelopedVerifiablePresentation' => 112,
  'JsonSchema' => 114,
  'JsonSchemaCredential' => 116,
  'VerifiableCredential' => 118,
  'VerifiablePresentation' => 120,
  '_sd' => 122,
  '_sd_alg' => 124,
  'aud' => 126,
  'cnf' => 128,
  'description' => 130,
  'digestMultibase' => 132,
  'digestSRI' => 134,
  'exp' => 136,
  'iat' => 138,
  'id' => 140,
  'iss' => 142,
  'jku' => 144,
  'kid' => 146,
  'mediaType' => 148,
  'name' => 150,
  'nbf' => 152,
  'sub' => 154,
  'type' => 156,
  'x5u' => 158,
  'AamvaDriversLicenseScannableInformation' => 160,
  'MachineReadableZone' => 162,
  'OpticalBarcodeCredential' => 164,
  'TerseBitstringStatusListEntry' => 166,
  'protectedComponentIndex' => 168,
  'did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj' => 170,
  'did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj#zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj' => 172,
  'did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj' => 174,
  'did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj#zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj' => 176,
  'https://sandbox.platform.veres.dev/statuses/z19rJ4oGrbFCqf3cNTVDHSbNd/status-lists' => 178,
  'confidenceMethod' => 180,
  'credentialSchema' => 182,
  'credentialStatus' => 184,
  'credentialSubject' => 186,
  'evidence' => 188,
  'issuer' => 190,
  'proof' => 192,
  'refreshService' => 194,
  'relatedResource' => 196,
  'renderMethod' => 198,
  'termsOfUse' => 200,
  'validFrom' => 202,
  'validUntil' => 204,
  'terseStatusListBaseUrl' => 206,
  'terseStatusListIndex' => 208,
  'challenge' => 210,
  'created' => 212,
  'cryptosuite' => 214,
  'domain' => 216,
  'expires' => 218,
  'nonce' => 220,
  'previousProof' => 222,
  'proofPurpose' => 224,
  'proofValue' => 226,
  'verificationMethod' => 228,
  'assertionMethod' => 230,
  'authentication' => 232,
  'capabilityDelegation' => 234,
  'capabilityInvocation' => 236,
  'keyAgreement' => 238
}

For more information on the above, see C.3 Implementation Notes.

This results in the following encoded credential:

Example 12: A CBOR-LD compressed Utopia Driver's License VC
D9CB1D821864A60183198000198001198002189D82187618A418B8A3189C18A618CE18B218D01AE592208118BAA2189C18A018A8447582002018BE18AA18C0A5189C186C18D60418E018E618E258417AB7C2E56B49E2CCE62184CE26818E15A8B173164401B5D3BB93FFD6D2B5EB8F6AC0971502AE3DD49D17EC66528164034C912685B8111BC04CDC9EC13DBADD91CC18E418AC

diagnostic:
51997([
  100,
  {
    1: [32768, 32769, 32770],
    157: [118, 164],
    184: {156: 166, 206: 178, 208: 3851559041},
    186: {156: 160, 168: h'75820020'},
    190: 170,
    192: {
      156: 108,
      214: 4,
      224: 230,
      226: h'7AB7C2E56B49E2CCE62184CE26818E15A8B173164401B5D3BB93FFD6D2B5EB8F6AC0971502AE3DD49D17EC66528164034C912685B8111BC04CDC9EC13DBADD91CC',
      228: 172
    }
  }
])

Encoding the Driver's License CBOR-LD as base64url and inserting the result into the PDF417 bytes in the 'ZZA' field in the 'ZZ' subfile:

Example 13: Bytes from a PDF417 including an encoded Utopia Driver's License VCB
bytes(@\n\x1e\rANSI 000000090002DL00410234ZZ02750202DLDAQF987654321\nDCSSMITH\nDDEN\nDACJOHN\nDDFN\nDADNONE\nDDGN\nDCAC\nDCBNONE\nDCDNONE\nDBD01012024\nDBB04191988\nDBA04192030\nDBC1\nDAU069 IN\nDAYBRO\nDAG123 MAIN ST\nDAIANYVILLE\nDAJUTO\nDAKF87P20000  \nDCFUTODOCDISCRIM\nDCGUTO\nDAW158\nDCK1234567890\nDDAN\rZZZZA2csdghhkpgGDGYAAGYABGYACGJ2CGHYYpBi4oxicGKYYzhiyGNAa5ZIggRi6ohicGKAYqER1ggAgGL4YqhjApRicGGwY1gQY4BjmGOJYQXq3wuVrSeLM5iGEziaBjhWosXMWRAG107uT/9bSteuPasCXFQKuPdSdF+xmUoFkA0yRJoW4ERvATNyewT263ZHMGOQYrA==\r)

The above can now be turned into a barcode:

A VCB from a Utopia driver's license.
Figure 6 A VCB from a Utopia driver's license.

C.1.2 Utopia Employment Authorization Document

We start with the data that will be signed by the VCB (i.e an MRZ):

Example 14: A Machine-Readable Zone that might appear on a Utopia EAD
IAUTO0000007010SRC0000000701<<
8804192M2601058NOT<<<<<<<<<<<5
SMITH<<JOHN<<<<<<<<<<<<<<<<<<<
C.1.2.1 Creating opticalDataBytes

For the EAD, we apply 3.2.4.4 Create opticalDataBytes:

Example 15: Data from the canonicalization of a Utopia EAD MRZ
canonicalizedData =
  'IAUTO0000007010SRC0000000701<<\n' +
  '8804192M2601058NOT<<<<<<<<<<<5\n' +
  'SMITH<<JOHN<<<<<<<<<<<<<<<<<<<\n'
opticalDataBytes:
[8, 198, 126, 183,  25, 160, 166, 112,
254, 184, 189,  47, 225, 211, 125, 210,
132, 137, 45,  86, 169,  28,  57, 165,
46, 253, 9, 137, 145,  42, 192, 113]

We can now use this hash value with 3.2.4.3 Hashing (ecdsa-xi-2023) to sign the VC. Executing 3.2.1 Encode OpticalBarcodeCredential without adding status, we get the following JSON-LD VC:

C.1.2.2 Example VC
Example 16: A JSON-LD VC for a Utopia EAD VCB
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/vc-barcodes/v1",
    "https://w3id.org/utopia/v2"
  ],
  "type": [
    "VerifiableCredential",
    "OpticalBarcodeCredential"
  ],
  "credentialSubject": {
    "type": "MachineReadableZone"
  },
  "issuer": "did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj",
  "proof": {
    "type": "DataIntegrityProof",
    "verificationMethod": "did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj#zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj",
    "cryptosuite": "ecdsa-xi-2023",
    "proofPurpose": "assertionMethod",
    "proofValue": "z4B8AQgjwgsEdcPEZkrkK2mTVKn7qufoDgDkv9Qitf9tjxQPMoJaGdXwDrThjp7LUdvzsDJ7UwYu6Xpm9fjbo6QnJ"
  }
}
C.1.2.3 CBOR-LD Compression and Encoding

We can now apply CBOR-LD compression to this VC. Here we use the newest version of CBOR-LD, however at the end of the section we provide VCBs encoded using older versions of CBOR-LD for interoperability testing with CBOR-LD implementations that are not up to date.

For this specficiation, we have reserved the CBOR-LD registry entry with value 100 (i.e., these payloads will begin with tag 0x0664). The parameters to encode using CBOR-LD, which can be found in the registry in the CBOR-LD specification, are then as follows:

Example 17: CBOR-LD encoding parameters
registryEntryId: 100
typeTable:
{
  "context":
    {
      "https://www.w3.org/ns/credentials/v2": 32768,
      "https://w3id.org/vc-barcodes/v1": 32769,
      "https://w3id.org/utopia/v2": 32770
    },

  "https://w3id.org/security#cryptosuiteString":
    {
      "ecdsa-rdfc-2019": 1,
      "ecdsa-sd-2023": 2,
      "eddsa-rdfc-2022": 3,
      "ecdsa-xi-2023": 4
    }
}

The term-to-ID mapping that should result from processing the contexts and assigning integer values to context terms is as follows:

Example 18: The term-to-ID map created by CBOR-LD when compressing a Utopia EAD
Map(95) {
  '@context' => 0,
  '@type' => 2,
  '@id' => 4,
  '@value' => 6,
  '@direction' => 8,
  '@graph' => 10,
  '@included' => 12,
  '@index' => 14,
  '@json' => 16,
  '@language' => 18,
  '@list' => 20,
  '@nest' => 22,
  '@reverse' => 24,
  '@base' => 26,
  '@container' => 28,
  '@default' => 30,
  '@embed' => 32,
  '@explicit' => 34,
  '@none' => 36,
  '@omitDefault' => 38,
  '@prefix' => 40,
  '@preserve' => 42,
  '@protected' => 44,
  '@requireAll' => 46,
  '@set' => 48,
  '@version' => 50,
  '@vocab' => 52,
  '...' => 100,
  'BitstringStatusList' => 102,
  'BitstringStatusListCredential' => 104,
  'BitstringStatusListEntry' => 106,
  'DataIntegrityProof' => 108,
  'EnvelopedVerifiableCredential' => 110,
  'EnvelopedVerifiablePresentation' => 112,
  'JsonSchema' => 114,
  'JsonSchemaCredential' => 116,
  'VerifiableCredential' => 118,
  'VerifiablePresentation' => 120,
  '_sd' => 122,
  '_sd_alg' => 124,
  'aud' => 126,
  'cnf' => 128,
  'description' => 130,
  'digestMultibase' => 132,
  'digestSRI' => 134,
  'exp' => 136,
  'iat' => 138,
  'id' => 140,
  'iss' => 142,
  'jku' => 144,
  'kid' => 146,
  'mediaType' => 148,
  'name' => 150,
  'nbf' => 152,
  'sub' => 154,
  'type' => 156,
  'x5u' => 158,
  'AamvaDriversLicenseScannableInformation' => 160,
  'MachineReadableZone' => 162,
  'OpticalBarcodeCredential' => 164,
  'TerseBitstringStatusListEntry' => 166,
  'protectedComponentIndex' => 168,
  'did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj' => 170,
  'did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj#zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj' => 172,
  'did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj' => 174,
  'did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj#zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj' => 176,
  'https://sandbox.platform.veres.dev/statuses/z19rJ4oGrbFCqf3cNTVDHSbNd/status-lists' => 178,
  'confidenceMethod' => 180,
  'credentialSchema' => 182,
  'credentialStatus' => 184,
  'credentialSubject' => 186,
  'evidence' => 188,
  'issuer' => 190,
  'proof' => 192,
  'refreshService' => 194,
  'relatedResource' => 196,
  'renderMethod' => 198,
  'termsOfUse' => 200,
  'validFrom' => 202,
  'validUntil' => 204,
  'challenge' => 206,
  'created' => 208,
  'cryptosuite' => 210,
  'domain' => 212,
  'expires' => 214,
  'nonce' => 216,
  'previousProof' => 218,
  'proofPurpose' => 220,
  'proofValue' => 222,
  'verificationMethod' => 224,
  'assertionMethod' => 226,
  'authentication' => 228,
  'capabilityDelegation' => 230,
  'capabilityInvocation' => 232,
  'keyAgreement' => 234
}

For more information on the above, see C.3 Implementation Notes.

Compression then results in the following encoded credential:

Example 19: A CBOR-LD compressed Utopia EAD VC
D9CB1D821864A50183198000198001198002189D82187618A418BAA1189C18A218BE18AE18C0A5189C186C18D20418DC18E218DE58417A9EC7F688F60CAA8C757592250B3F6D6E18419941F186E1ED4245770E687502D51D01CD2C2295E4338178A51A35C2F044A85598E15DB9AEF00261BC5C95A744E718E018B0

diagnostic:
51997([
  100,
  {
    1: [32768, 32769, 32770],
    157: [118, 164],
    186: {156: 162},
    190: 174,
    192: {
      156: 108,
      210: 4,
      220: 226,
      222: h'7A9EC7F688F60CAA8C757592250B3F6D6E18419941F186E1ED4245770E687502D51D01CD2C2295E4338178A51A35C2F044A85598E15DB9AEF00261BC5C95A744E7',
      224: 176
    }
  }
])

Encoding the EAD CBOR-LD as base45-multibase and prepending 'VC1-':

Example 20: An encoded Utopia EAD VCB
VC1-R0OR*W3Y33V%K PG88G3A3B60A8G1534KG$-ENXKWQN053653Y53I53 539*K0XJ.TDYOQJ63P63L6337BPMFPCP7EH2R12YH%%EXU4$08E-D8D86F8E2HX:T8Z8/ 1TZEH.QBA03Q5W.I0N6FBF4E3:SOQU8. A3MSELNHFU0GCVVBP6LU9T%ES-3

The above can now be turned into a QR code:

C.1.2.4 Employment Authorization Document
A VCB from a Utopia EAD.
Figure 7 A VCB from a Utopia EAD.

For use with the following MRZ:

An MRZ on a Utopia Employment Authorization Document.
Figure 8 An MRZ on a Utopia Employment Authorization Document.

C.2 Verifying VCBs

We now apply the reverse process to verify.

C.2.1 Utopia Driver's License

C.2.1.1 Decoding and Decompressing

We first read the data from the PDF417:

Example 21: Bytes from a PDF417 including an encoded Utopia Driver's License VCB
bytes(@\n\x1e\rANSI 000000090002DL00410234ZZ02750202DLDAQF987654321\nDCSSMITH\nDDEN\nDACJOHN\nDDFN\nDADNONE\nDDGN\nDCAC\nDCBNONE\nDCDNONE\nDBD01012024\nDBB04191988\nDBA04192030\nDBC1\nDAU069 IN\nDAYBRO\nDAG123 MAIN ST\nDAIANYVILLE\nDAJUTO\nDAKF87P20000  \nDCFUTODOCDISCRIM\nDCGUTO\nDAW158\nDCK1234567890\nDDAN\rZZZZA2csdghhkpgGDGYAAGYABGYACGJ2CGHYYpBi4oxicGKYYzhiyGNAa5ZIggRi6ohicGKAYqER1ggAgGL4YqhjApRicGGwY1gQY4BjmGOJYQXq3wuVrSeLM5iGEziaBjhWosXMWRAG107uT_9bSteuPasCXFQKuPdSdF-xmUoFkA0yRJoW4ERvATNyewT263ZHMGOQYrA==\r)

We extract the data in field 'ZZA' in subfile 'ZZ', undoing the base encoding:

Example 22: A Utopia Driver's License VC compressed with CBOR-LD
D9CB1D821864A60183198000198001198002189D82187618A418B8A3189C18A618CE18B218D01AE592208118BAA2189C18A018A8447582002018BE18AA18C0A5189C186C18D60418E018E618E258417AB7C2E56B49E2CCE62184CE26818E15A8B173164401B5D3BB93FFD6D2B5EB8F6AC0971502AE3DD49D17EC66528164034C912685B8111BC04CDC9EC13DBADD91CC18E418AC

We now decompress with CBOR-LD to get the original JSON-LD VC to be verified. Again, the parameters are associated with CBOR-LD registry entry 100.

Example 23: CBOR-LD decoding parameters
typeTable:
{
  "context":
    {
      "https://www.w3.org/ns/credentials/v2": 32768,
      "https://w3id.org/vc-barcodes/v1": 32769,
      "https://w3id.org/utopia/v2": 32770
    },

  "https://w3id.org/security#cryptosuiteString":
    {
      "ecdsa-rdfc-2019": 1,
      "ecdsa-sd-2023": 2,
      "eddsa-rdfc-2022": 3,
      "ecdsa-xi-2023": 4
    }
}

The ID-to-term mapping that should result from processing the contexts and assigning integer values to context terms is as follows. Note that this is the inverse of the map constructed during compression.

Example 24: The ID-to-term map created by CBOR-LD when decompressing a Utopia DL
Map(97) {
  0 => '@context',
  2 => '@type',
  4 => '@id',
  6 => '@value',
  8 => '@direction',
  10 => '@graph',
  12 => '@included',
  14 => '@index',
  16 => '@json',
  18 => '@language',
  20 => '@list',
  22 => '@nest',
  24 => '@reverse',
  26 => '@base',
  28 => '@container',
  30 => '@default',
  32 => '@embed',
  34 => '@explicit',
  36 => '@none',
  38 => '@omitDefault',
  40 => '@prefix',
  42 => '@preserve',
  44 => '@protected',
  46 => '@requireAll',
  48 => '@set',
  50 => '@version',
  52 => '@vocab',
  100 => '...',
  102 => 'BitstringStatusList',
  104 => 'BitstringStatusListCredential',
  106 => 'BitstringStatusListEntry',
  108 => 'DataIntegrityProof',
  110 => 'EnvelopedVerifiableCredential',
  112 => 'EnvelopedVerifiablePresentation',
  114 => 'JsonSchema',
  116 => 'JsonSchemaCredential',
  118 => 'VerifiableCredential',
  120 => 'VerifiablePresentation',
  122 => '_sd',
  124 => '_sd_alg',
  126 => 'aud',
  128 => 'cnf',
  130 => 'description',
  132 => 'digestMultibase',
  134 => 'digestSRI',
  136 => 'exp',
  138 => 'iat',
  140 => 'id',
  142 => 'iss',
  144 => 'jku',
  146 => 'kid',
  148 => 'mediaType',
  150 => 'name',
  152 => 'nbf',
  154 => 'sub',
  156 => 'type',
  158 => 'x5u',
  160 => 'AamvaDriversLicenseScannableInformation',
  162 => 'MachineReadableZone',
  164 => 'OpticalBarcodeCredential',
  166 => 'TerseBitstringStatusListEntry',
  168 => 'protectedComponentIndex',
  170 => 'did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj',
  172 => 'did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj#zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj',
  174 => 'did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj',
  176 => 'did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj#zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj',
  178 => 'https://sandbox.platform.veres.dev/statuses/z19rJ4oGrbFCqf3cNTVDHSbNd/status-lists',
  180 => 'confidenceMethod',
  182 => 'credentialSchema',
  184 => 'credentialStatus',
  186 => 'credentialSubject',
  188 => 'evidence',
  190 => 'issuer',
  192 => 'proof',
  194 => 'refreshService',
  196 => 'relatedResource',
  198 => 'renderMethod',
  200 => 'termsOfUse',
  202 => 'validFrom',
  204 => 'validUntil',
  206 => 'terseStatusListBaseUrl',
  208 => 'terseStatusListIndex',
  210 => 'challenge',
  212 => 'created',
  214 => 'cryptosuite',
  216 => 'domain',
  218 => 'expires',
  220 => 'nonce',
  222 => 'previousProof',
  224 => 'proofPurpose',
  226 => 'proofValue',
  228 => 'verificationMethod',
  230 => 'assertionMethod',
  232 => 'authentication',
  234 => 'capabilityDelegation',
  236 => 'capabilityInvocation',
  238 => 'keyAgreement'
}

For more information on the above, see C.3 Implementation Notes.

Decompression then yields the following credential:

Example 25: A JSON-LD VC for a Utopia Driver's License VCB
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/vc-barcodes/v1",
    "https://w3id.org/utopia/v2"
  ],
  "type": [
    "VerifiableCredential",
    "OpticalBarcodeCredential"
  ],
  "credentialSubject": {
    "type": "AamvaDriversLicenseScannableInformation",
    "protectedComponentIndex": "uggAg"
  },
  "issuer": "did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj",
  "credentialStatus": {
    "type": "TerseBitstringStatusListEntry",
    "terseStatusListBaseUrl": "https://sandbox.platform.veres.dev/statuses/z19rJ4oGrbFCqf3cNTVDHSbNd/status-lists",
    "terseStatusListIndex": 3851559041
  },
  "proof": {
    "type": "DataIntegrityProof",
    "verificationMethod": "did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj#zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj",
    "cryptosuite": "ecdsa-xi-2023",
    "proofPurpose": "assertionMethod",
    "proofValue": "z4g6G3dAZhhtPxPWgFvkiRv7krtCaeJxjokvL46fchAFCXEY3FeX2vn46MDgBaw779g1E1jswZJxxreZDCrtHg2qH"
  }
}
C.2.1.2 Verifying

We apply 3.2.4.4 Create opticalDataBytes to create the opticalDataBytes that ecdsa-xi-2023 requires, using the scanned PDF417 and protectedComponentIndex as input.

Example 26: A canonicalization of a Utopia Driver's License PDF417
canonicalizedData = 'DACJOHN\nDAQ987654321\nDCSSMITH\n'
opticalDataBytes:
  [188,  38, 200, 146, 227, 213,  90, 250,
  50,  18, 126, 254,  47, 177,  91,  23,
  64, 129, 104, 223, 136,  81, 116,  67,
  136, 125, 137, 165, 117,  63, 152, 207]

We then apply 3.2.4.3 Hashing (ecdsa-xi-2023) and 3.2.4.2 Verify Proof (ecdsa-xi-2023) to verify the credential.

C.2.1.3 Status Checking

The last step is to check the status information on the Driver's License credential. We apply 3.2.3.1 TerseBitstringStatusListEntry to BitstringStatusListEntry to convert the TerseBitstringStatusListEntry into a BitstringStatusListEntry. Here we check two status types, 'revocation' and 'suspension', passing those strings as values of statusPurpose.

Example 27: A BitstringStatusListEntry for status purpose: revocation
{
  type: 'BitstringStatusListEntry',
  statusListCredential: 'https://sandbox.platform.veres.dev/statuses/z19rJ4oGrbFCqf3cNTVDHSbNd/status-lists/revocation/29385',
  statusListIndex: 8321,
  statusPurpose: 'revocation'
}
Example 28: A BitstringStatusListEntry for status purpose: suspension
{
  type: 'BitstringStatusListEntry',
  statusListCredential: 'https://sandbox.platform.veres.dev/statuses/z19rJ4oGrbFCqf3cNTVDHSbNd/status-lists/suspension/29385',
  statusListIndex: 8321,
  statusPurpose: 'suspension'
}

These can then be validated as in the Bitstring Status List v1.0: Validate Algorithm.

C.2.2 Utopia Employment Authorization Document

C.2.2.1 Decoding and Decompressing

We first read the data from the QR code:

Example 29: An encoded Utopia Driver's License EAD
VC1-R0OR*W3Y33V%K PG88G3A3B60A8G1534KG$-ENXKWQN053653Y53I53 539*K0XJ.TDYOQJ63P63L6337BPMFPCP7EH2R12YH%%EXU4$08E-D8D86F8E2HX:T8Z8/ 1TZEH.QBA03Q5W.I0N6FBF4E3:SOQU8. A3MSELNHFU0GCVVBP6LU9T%ES-3

We extract the data after 'VC1-' undoing the base encoding:

Example 30: A CBOR-LD compressed Utopia EAD VC
D9CB1D821864A50183198000198001198002189D82187618A418BAA1189C18A218BE18AE18C0A5189C186C18D20418DC18E218DE58417A9EC7F688F60CAA8C757592250B3F6D6E18419941F186E1ED4245770E687502D51D01CD2C2295E4338178A51A35C2F044A85598E15DB9AEF00261BC5C95A744E718E018B0

We now decompress with CBOR-LD to get the original JSON-LD VC to be verified. Again, the parameters are associated with CBOR-LD registry entry 100.

Example 31: CBOR-LD decoding parameters
typeTable:
{
  "context":
    {
      "https://www.w3.org/ns/credentials/v2": 32768,
      "https://w3id.org/vc-barcodes/v1": 32769,
      "https://w3id.org/utopia/v2": 32770
    },

  "https://w3id.org/security#cryptosuiteString":
    {
      "ecdsa-rdfc-2019": 1,
      "ecdsa-sd-2023": 2,
      "eddsa-rdfc-2022": 3,
      "ecdsa-xi-2023": 4
    }
}

The ID-to-term mapping that should result from processing the contexts and assigning integer values to context terms is as follows. Note that this is the inverse of the map constructed during compression.

Example 32: The ID-to-term map created by CBOR-LD when decompressing a Utopia EAD
Map(95) {
  0 => '@context',
  2 => '@type',
  4 => '@id',
  6 => '@value',
  8 => '@direction',
  10 => '@graph',
  12 => '@included',
  14 => '@index',
  16 => '@json',
  18 => '@language',
  20 => '@list',
  22 => '@nest',
  24 => '@reverse',
  26 => '@base',
  28 => '@container',
  30 => '@default',
  32 => '@embed',
  34 => '@explicit',
  36 => '@none',
  38 => '@omitDefault',
  40 => '@prefix',
  42 => '@preserve',
  44 => '@protected',
  46 => '@requireAll',
  48 => '@set',
  50 => '@version',
  52 => '@vocab',
  100 => '...',
  102 => 'BitstringStatusList',
  104 => 'BitstringStatusListCredential',
  106 => 'BitstringStatusListEntry',
  108 => 'DataIntegrityProof',
  110 => 'EnvelopedVerifiableCredential',
  112 => 'EnvelopedVerifiablePresentation',
  114 => 'JsonSchema',
  116 => 'JsonSchemaCredential',
  118 => 'VerifiableCredential',
  120 => 'VerifiablePresentation',
  122 => '_sd',
  124 => '_sd_alg',
  126 => 'aud',
  128 => 'cnf',
  130 => 'description',
  132 => 'digestMultibase',
  134 => 'digestSRI',
  136 => 'exp',
  138 => 'iat',
  140 => 'id',
  142 => 'iss',
  144 => 'jku',
  146 => 'kid',
  148 => 'mediaType',
  150 => 'name',
  152 => 'nbf',
  154 => 'sub',
  156 => 'type',
  158 => 'x5u',
  160 => 'AamvaDriversLicenseScannableInformation',
  162 => 'MachineReadableZone',
  164 => 'OpticalBarcodeCredential',
  166 => 'TerseBitstringStatusListEntry',
  168 => 'protectedComponentIndex',
  170 => 'did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj',
  172 => 'did:key:zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj#zDnaeWjKfs1ob9QcgasjYSPEMkwq31hmvSAWPVAgnrt1e9GKj',
  174 => 'did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj',
  176 => 'did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj#zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj',
  178 => 'https://sandbox.platform.veres.dev/statuses/z19rJ4oGrbFCqf3cNTVDHSbNd/status-lists',
  180 => 'confidenceMethod',
  182 => 'credentialSchema',
  184 => 'credentialStatus',
  186 => 'credentialSubject',
  188 => 'evidence',
  190 => 'issuer',
  192 => 'proof',
  194 => 'refreshService',
  196 => 'relatedResource',
  198 => 'renderMethod',
  200 => 'termsOfUse',
  202 => 'validFrom',
  204 => 'validUntil',
  206 => 'challenge',
  208 => 'created',
  210 => 'cryptosuite',
  212 => 'domain',
  214 => 'expires',
  216 => 'nonce',
  218 => 'previousProof',
  220 => 'proofPurpose',
  222 => 'proofValue',
  224 => 'verificationMethod',
  226 => 'assertionMethod',
  228 => 'authentication',
  230 => 'capabilityDelegation',
  232 => 'capabilityInvocation',
  234 => 'keyAgreement'
}

For more information on the above, see C.3 Implementation Notes.

Decompression then yields the following credential:

Example 33: A JSON-LD VC for a Utopia EAD VCB
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://w3id.org/vc-barcodes/v1",
    "https://w3id.org/utopia/v2"
  ],
  "type": [
    "VerifiableCredential",
    "OpticalBarcodeCredential"
  ],
  "credentialSubject": {
    "type": "MachineReadableZone"
  },
  "issuer": "did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj",
  "proof": {
    "type": "DataIntegrityProof",
    "verificationMethod": "did:key:zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj#zDnaeZSD9XcuULaS8qmgDUa6TMg2QjF9xABnZK42awDH3BEzj",
    "cryptosuite": "ecdsa-xi-2023",
    "proofPurpose": "assertionMethod",
    "proofValue": "z4B8AQgjwgsEdcPEZkrkK2mTVKn7qufoDgDkv9Qitf9tjxQPMoJaGdXwDrThjp7LUdvzsDJ7UwYu6Xpm9fjbo6QnJ"
  }
}
C.2.2.2 Verifying

We apply 3.2.4.4 Create opticalDataBytes to create the opticalDataBytes that ecdsa-xi-2023 requires,using the MRZ on the EAD as input for the EAD:

Example 34: A canonicalization of a Utopia EAD MRZ
canonicalizedData =
  'IAUTO0000007010SRC0000000701<<\n' +
  '8804192M2601058NOT<<<<<<<<<<<5\n' +
  'SMITH<<JOHN<<<<<<<<<<<<<<<<<<<\n'
opticalDataBytes:
[8, 198, 126, 183,  25, 160, 166, 112,
254, 184, 189,  47, 225, 211, 125, 210,
132, 137, 45,  86, 169,  28,  57, 165,
46, 253, 9, 137, 145,  42, 192, 113]

We then apply 3.2.4.3 Hashing (ecdsa-xi-2023) and 3.2.4.2 Verify Proof (ecdsa-xi-2023) to verify the credential.

C.3 Implementation Notes

C.3.1 CBOR-LD

When building maps from context terms to CBOR-LD integers, note that some contexts include other contexts inside of them, nested under particular types of objects. These nested contexts are called "type-scoped contexts" and they only become active when the associated type is used in the data. This is important for term ID assignment because the terms in a context are only assigned IDs once that context becomes active. In these test vectors, this is why the maps created for the Driver's License and the Employment Authorization Document are different even though the two credentials use identical contexts.

In addition, note that odd numbers are used in CBOR-LD to express terms when the associated value is plural. For example, in the CBOR-LD term-to-ID and ID-to-term maps above, "type" is mapped to 156, but in places where multiple types are expressed in a VC, 157 is used instead.

C.4 Legacy CBOR-LD encoded credentials

This process is used to test whether a CBOR-LD implementation that is not fully up to date has been used.

C.4.1 CBOR-LD Version 6.X

The process remains the same, with the exception of the CBOR-LD decoding step, for which the following appContextMap should be used:
Example 35: A BitstringStatusListEntry for status purpose: suspension
appContextMap:
[['https://www.w3.org/ns/credentials/v2', 32768],
['https://w3id.org/vc-barcodes/v1', 32769],
['https://w3id.org/utopia/v2', 32770]]
C.4.1.1 Utopia Driver's License
A VCB from a Utopia driver's license encoded with legacy CBOR-LD.
Figure 9 A VCB from a Utopia driver's license encoded with legacy CBOR-LD.
C.4.1.2 Utopia Employment Authorization Document
A VCB from a Utopia EAD encoded with legacy CBOR-LD.
Figure 10 A VCB from a Utopia EAD encoded with legacy CBOR-LD.

For use with the following MRZ:

An MRZ on a Utopia Employment Authorization Document.
Figure 11 An MRZ on a Utopia Employment Authorization Document.

C.4.2 CBOR-LD Version 7.X

C.4.2.1 Utopia Driver's License
A VCB from a Utopia driver's license encoded with legacy CBOR-LD.
Figure 12 A VCB from a Utopia driver's license encoded with legacy CBOR-LD.
C.4.2.2 Utopia Employment Authorization Document
A VCB from a Utopia EAD encoded with legacy CBOR-LD.
Figure 13 A VCB from a Utopia EAD encoded with legacy CBOR-LD.

For use with the following MRZ:

An MRZ on a Utopia Employment Authorization Document.
Figure 14 An MRZ on a Utopia Employment Authorization Document.

D. Revision History

This section is non-normative.

This section contains the substantive changes that have been made to this specification over time.

Issue 2: Content will be filled in after standards-track has been started

The content for this specification will be filled in after the standards-track process has been started.

E. References

E.1 Normative references

[aamva-dl-id-card-design-standard]
AAMVA DL/ID Card Design Standard (2020). American Association of Motor Vehicle Administrators. 2020. URL: https://www.aamva.org/assets/best-practices,-guides,-standards,-manuals,-whitepapers/aamva-dl-id-card-design-standard-(2020)
[CBOR-LD]
Compact Binary Object Representation for Linked Data v1.0. URL: https://w3c.github.io/cbor-ld/
[CID]
Controlled Identifiers v1.0. Michael Jones; Manu Sporny. W3C. 15 May 2025. W3C Recommendation. URL: https://www.w3.org/TR/cid-1.0/
[ICAO9303-3]
Machine Readable Travel Documents Part 3: Specifications Common to all MRTDs, Eighth Edition, 2021. ICAO. International Civil Aviation Organization. 2021. URL: https://www.icao.int/publications/Documents/9303_p3_cons_en.pdf
[infra]
Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/info/rfc2119/
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/info/rfc8174/
[URL]
URL Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://url.spec.whatwg.org/
[VC-BITSTRING-STATUS-LIST]
Bitstring Status List v1.0. Manu Sporny; Dave Longley; Mahmoud Alkhraishi; Michael Prorock. W3C. 15 May 2025. W3C Recommendation. URL: https://www.w3.org/TR/vc-bitstring-status-list/
[VC-DATA-INTEGRITY]
Verifiable Credential Data Integrity 1.0. Ivan Herman; Manu Sporny; Ted Thibodeau Jr; Dave Longley; Greg Bernstein. W3C. 15 May 2025. W3C Recommendation. URL: https://www.w3.org/TR/vc-data-integrity/
[VC-DATA-MODEL-2.0]
Verifiable Credentials Data Model v2.0. Ivan Herman; Michael Jones; Manu Sporny; Ted Thibodeau Jr; Gabe Cohen. W3C. 15 May 2025. W3C Recommendation. URL: https://www.w3.org/TR/vc-data-model-2.0/
[VC-DI-ECDSA]
Data Integrity ECDSA Cryptosuites v1.0. Manu Sporny; Dave Longley; Greg Bernstein. W3C. 15 May 2025. W3C Recommendation. URL: https://www.w3.org/TR/vc-di-ecdsa/
[XPATH-FUNCTIONS]
XQuery 1.0 and XPath 2.0 Functions and Operators (Second Edition). Ashok Malhotra; Jim Melton; Norman Walsh; Michael Kay. W3C. 14 December 2010. W3C Recommendation. URL: https://www.w3.org/TR/xpath-functions/

E.2 Informative references

[ISO15438-2015]
ISO/IEC 15438:2015: PDF417 Bar Code Symbology Specification. ISO/IEC JTC 1/SC 31. International Standards Organization. 2015. URL: https://www.iso.org/standard/65502.html
[ISO18013-2]
ISO/IEC 18013-2:2020: Personal identification — ISO-compliant driving licence — Part 2: Machine-readable technologies. ISO/IEC JTC 1/SC 17. International Standards Organization. 2020. URL: https://www.iso.org/standard/70486.html