CBOR-LD 1.0

A CBOR-based Serialization for Linked Data

W3C Working Draft

More details about this document
This version:
https://www.w3.org/TR/2026/WD-cbor-ld-10-20260630/
Latest published version:
https://www.w3.org/TR/cbor-ld-10/
Latest editor's draft:
https://w3c.github.io/cbor-ld/
History:
https://www.w3.org/standards/history/cbor-ld-10/
Commit history
Editors:
Manu Sporny (Digital Bazaar)
Dave Longley (Digital Bazaar)
Wesley Smith (Digital Bazaar)
Authors:
Manu Sporny (Digital Bazaar)
Dave Longley (Digital Bazaar)
Feedback:
GitHub w3c/cbor-ld (pull requests, new issue, open issues)

Abstract

CBOR is a compact binary data serialization and messaging format. This specification defines CBOR-LD 1.0, a CBOR-based format to serialize Linked Data. The encoding is designed to leverage the existing JSON-LD ecosystem, which is deployed on hundreds of millions of systems today, to provide a compact serialization format for those seeking efficient encoding schemes for Linked Data. By utilizing semantic compression schemes, compression ratios in excess of 60% better than generalized compression schemes are possible. This format is primarily intended to be a way to use Linked Data in storage and bandwidth constrained programming environments, to build interoperable semantic wire-level protocols, and to efficiently store Linked Data in CBOR-based storage engines.

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 is experimental.

There is a reference implementation that is capable of demonstrating the features described in this document.

This document was published by the JSON-LD 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

This section is non-normative.

CBOR is a compact binary data serialization and messaging format. This specification defines CBOR-LD 1.0, a CBOR-based format to serialize Linked Data. The encoding is designed to leverage the existing JSON-LD ecosystem, which is deployed on hundreds of millions of systems today, to provide a compact serialization format for those seeking efficient encoding schemes for Linked Data. By utilizing semantic compression schemes, compression ratios in excess of 60% better than generalized compression schemes are possible. This format is primarily intended to be a way to use Linked Data in storage and bandwidth constrained programming environments, to build interoperable semantic wire-level protocols, and to efficiently store Linked Data in CBOR-based storage engines.

1.1 How to Read this Document

This section is non-normative.

This document is a detailed specification for a serialization of Linked Data in CBOR. The document is primarily intended for the following audiences:

1.1.1 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 word MUST in this document is to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, it appears in all capitals, as shown here.

1.2 Contributing

This section is non-normative.

There are a number of ways that one may participate in the development of this specification:

1.3 Design Goals and Rationale

This section is non-normative.

CBOR-LD satisfies the following design goals:

Simplicity
Implementations should be simple to implement given an existing JSON-LD implementation.
Efficient Storage
The encoding process should generate an aggressively compact Linked Data binary format.
Generalized Algorithm
The encoding algorithm must be generalized.
Semantic Compression
The encoding format should maximize compression of Linked Data URLs (terms and values). Focusing here ensures that the algorithms can achieve compression ratios better than generalized compression algorithms.
Raw Binary
Base-encoded binary values, and other compressible data types, should be translated to their raw binary forms from base-encoded formats when possible without sacrificing generality.

Similarly, the following are non-goals.

The following minefields have been identified while working on this specification:

2. Basic Concept

This section is non-normative.

At a high level, CBOR-LD is a compact, binary serialization for JSON-LD that allows the following mechanisms for additional compression:

Codecs are the basic primitive for compressing typed values in a generic way. Semantic compression is for compressing JSON-LD terms. Registry dictionaries are for compressing typed values in a use-case-specific way. Each of these is optional — CBOR-LD can be used with any, all, or none of these compression strategies. Taken together, the set of these strategies that is used for a particular use case is known as a processing model.

3. Semantic Compression

This section is non-normative.

Semantic compression is a powerful tool for creating compact CBOR-LD payloads. The core idea is to use the information content of external JSON-LD context objects to compress JSON-LD terms. These external context objects are available to both the creator and the consumer of the payload, so this is done in an invertible way.

The general semantic compression process is to take a JSON-LD Document and do the following:

  1. Determine whether JSON-LD can be compressed (find @context values in JSON-LD document that reference contexts via URIs; embedded context values cannot be compressed).
  2. Process the JSON-LD contexts, building a CBOR-LD term-codec map — a list of all terms that can be compressed. Sort the list (into Unicode code point order). Associate byte values with each term, starting at 0 and counting up.
  3. Encode the JSON-LD Document into CBOR-LD. This consists of replacing every key with the byte value associated with the term from the term-codec map.
  4. If and when the original JSON-LD is required, decoding from CBOR-LD to JSON-LD consists of replacing every CBOR byte value with the associated key from the term-codec map.

4. CBOR Tags for CBOR-LD

CBOR-LD payloads need to be identifiable as such at the binary level. CBOR natively supports this via its "tag" feature — a header value in the binary data that describes the rest of the payload via a global registry.

The CBOR tag 0xCB1D (tag value 51997) has been registered in the IANA CBOR tag registry to be used for CBOR-LD. The data that immediately follows this tag value identifies the registry entry that was used to create the compressed payload.

CBOR-LD payloads MUST be structured such that the item tagged with tag 0xCB1D is a two-element array, and the first element MUST be a major type 0 integer. This integer is a CBOR-LD Registry Entry ID. The binary structure is tag([registryEntryId, payload]).

The value of the CBOR-LD Registry Entry ID is then used to look up a CBOR-LD Registry Entry in the CBOR-LD Registry.

4.1 CBOR-LD Registry

To enable unbounded extension of possible use cases for CBOR-LD that require different compression table material for consumption while working with a single CBOR tag value, we define the following.

The CBOR-LD Registry is a global list that provides consumers of CBOR-LD payloads the information they need to reconstruct the term-codec map required for decompression. A CBOR-LD Registry Entry contains the following:

The string "callerProvidedTable", may appear in typeTables, denoting that for this use case, a Type Table is required which is not globally defined.

4.1.1 Registry

The current CBOR-LD Registry can be found here.

To register an entry, follow the instructions in the README. The registry is owned by the W3C JSON-LD Community Group.

5. Algorithms

In this section, we specify the algorithms required to convert JSON-LD to CBOR-LD and vice versa. The majority of the algorithms in this section relate to the semantic compression feature and are not used in conversions between CBOR-LD and JSON-LD where the CBOR-LD payload does not use semantic compression.

5.1 Encoding and Decoding

5.1.1 JSON-LD to CBOR-LD Encoding Algorithm

This algorithm takes a map typeTable, an integer registryEntryId, and a JSON-LD document jsonldDocument as inputs, and returns a hexadecimal string cborldBytes.

  1. Set prefix to the result of passing registryEntryId to 5.6.1 Get CBOR Tag Structure Algorithm.
  2. Set state to an empty map.
  3. If the registry entry associated with registryEntryId requires semantic compression:
    1. Set state.strategy to "compression".
    2. Set state.typeTable to typeTable.
    3. Set state.registryEntryId to registryEntryId.
    4. Set state to the result of passing state to 5.2.1 Initialize Conversion Algorithm.
    5. Set output to the result of passing state and jsonldDocument as inputDocument to 5.2.2 Convert Document Algorithm.
    6. Set suffix to the CBOR encoding of output.
  4. Otherwise, set suffix to the CBOR encoding of jsonldDocument.
  5. Set cborldBytes to a hexidecimal encoding of prefix prepended to suffix.
  6. Return cborldBytes.

5.1.2 CBOR-LD to JSON-LD Decoding Algorithm

This algorithm takes a CBOR-LD payload cborldBytes, and returns a JSON-LD document jsonldDocument.

  1. Set result to the result of passing cborldBytes to 5.6.2 Get Registry Entry ID Algorithm.
  2. Set state.registryEntryId to result.registryEntryId and suffix to result.suffix.
  3. Set state to an empty map.
  4. If the registry entry associated with state.registryEntryId uses semantic compression:
    1. Set state.strategy to "decompression".
    2. For each entry type: map in the typeTables array in the CBOR-LD Varint Registry Entry associated with registryEntryId, add that entry to state.typeTable, and set the value of type in state.reverseTypeTable to inverseMap, where inverseMap is map with the mapping inverted.
    3. Set state to the result of passing state to 5.2.1 Initialize Conversion Algorithm.
    4. Set input to the result of decoding suffix from bytes to a map.
    5. Set jsonldDocument to the result of passing state and input as inputDocuments to 5.2.2 Convert Document Algorithm.
  5. Otherwise, set jsonldDocument to the result of parsing cborldBytes.
  6. Return jsonldDocument.

5.2 Conversion Algorithms

The algorithms in this section describe the behavior of a "converter" for abstractly converting inputs between data forms. When used in conjunction with a "strategy", such as the "compression" and "decompression" strategies defined later in this section, these algorithms can be instantiated to convert between concrete data forms. The "compression" strategy converts from JSON-LD to CBOR-LD, while the "decompression" strategy converts from CBOR-LD to JSON-LD.

5.2.1 Initialize Conversion Algorithm

This algorithm takes and returns a map state.

  1. Set state to the result of passing state to 5.4.1 Initialize Context Loader Algorithm.
  2. Set state.initialActiveContext to the result of passing empty maps termMap and previousActiveContext to 5.3.1 Initialize Active Context Algorithm.
  3. Set state.typesEncodedAsBytes to an empty set.
  4. Add "none", "http://www.w3.org/2001/XMLSchema#date", "http://www.w3.org/2001/XMLSchema#dateTime", and "url" to state.typesEncodedAsBytes.
  5. Return state.

5.2.2 Convert Document Algorithm

This algorithm takes a map state and a map or array of maps inputDocuments, and returns a map containing a map state and a map or array of maps outputMaps.

  1. If inputDocuments is an array, set inputs to inputDocuments. Otherwise, set inputs to [inputDocuments].
  2. Set outputMaps to an empty array.
  3. For input in inputs:
    1. Set output to an empty map.
    2. Set result to the result of passing state, input, output, and state.initialActiveContext as activeContext to 5.2.3 General Conversion Algorithm.
    3. Add result.output to outputMaps.
    4. Set state to result.state.
  4. If inputDocuments is an array, return outputMaps. Otherwise, return the first element of outputMaps.

5.2.3 General Conversion Algorithm

This algorithm takes maps input, output, state, and activeContext as inputs, and returns a map containing maps state and output.

  1. If state.strategy is set to "compression":
    1. Set contextConversionResult to the result of 5.2.5.1 Convert Contexts for Compression Algorithm, passing state, activeContext, input, and output.
    2. Set activeContext to contextConversionResult.activeContext, output to contextConversionResult.output, and state to contextConversionResult.state.
  2. Otherwise, set activeContext to result.activeContext and state to result.state of result resulting from 5.2.6.1 Convert Contexts for Decompression Algorithm, passing state, activeContext, input, and output.
  3. If state.strategy is set to "compression", set state to result.state and objectTypes to result.objectTypes for result resulting from 5.2.5.4 Get Object Types for Compression Algorithm, passing state, activeContext, input, and output.
  4. Otherwise, set state to result.state and objectTypes to result.objectTypes for result resulting from 5.2.6.4 Get Object Types for Decompression Algorithm, passing state, activeContext, input, and output.
  5. Set activeContext to the result of passing activeContext and objectTypes to 5.3.4 Apply Type Scoped Contexts Algorithm.
  6. If state.strategy is set to "compression", set state to result.state and termEntries to result.termEntries for result resulting from 5.2.5.3 Get Input Entries for Compression Algorithm, passing state, input, and activeContext.
  7. Otherwise, set state to result.state, output to result.output, and termEntries to result.termEntries for result resulting from 5.2.6.3 Get Input Entries for Decompression Algorithm, passing state, input, output, and activeContext.
  8. For [termInfo, value] in termEntries:
    1. Set term to termInfo.term.
    2. Set valueActiveContext to the result of passing activeContext and term to 5.3.3 Apply Property Scoped Contexts Algorithm.
    3. Set plural to the value of termInfo.plural and termType to the value of @type in termInfo.def.
    4. If plural is set to true, set values to the value of value. Otherwise, set values to an array containing the value of value as a single element.
    5. Set outputs to an empty array.
    6. For unconvertedValue in values:
      1. Set result to the result of 5.2.4 Convert Value Algorithm, passing state, termType, unconvertedValue as value, and valueActiveContext as activeContext.
      2. Set state to result.state and add result.output to outputs.
    7. If plural is set to true, set outputValues to outputs. Otherwise, set outputValues to the first element of outputs.
    8. If state.strategy is set to "compression", set the value of termInfo.termId to map to outputValues in output. Otherwise, set the value of termInfo.term to map to outputValues in output.
  9. Set result to be an empty map.
  10. Set result.state to state and result.output to output.
  11. Return result.

5.2.4 Convert Value Algorithm

This algorithm takes maps state, activeContext, termInfo, and values value and termType. It returns a result object containing maps state and output.

  1. If value is null, return null.
  2. If state.strategy is set to "compression", set output to the result of passing state, termType, termInfo, and value to 5.2.5.2 Convert Value for Compression Algorithm.
  3. Otherwise, set output to the result of passing state, termType, termInfo, and value to 5.2.6.2 Convert Value for Decompression Algorithm.
  4. If output is defined, return result, a map contatining state and output.
  5. If value is an array:
    1. Set outputs to be an empty array.
    2. For element of value:
      1. Let result be the result of 5.2.4 Convert Value Algorithm, passing activeContext, state, termInfo, termType, and element as value. Set state to result.state and add result.output to outputs.
    3. Set result to be an empty map. Set result.state to state and result.output to outputs.
    4. Return result.
  6. Set output to an empty map.
  7. Set result to the result of 5.2.3 General Conversion Algorithm, passing state, activeContext, value as input, and output.
  8. Return result.

5.2.5 Compression Strategy Algorithms

The algorithms in this section define the "compression" strategy to be used with the "conversion" algorithms defined previously to convert JSON-LD to CBOR-LD.

5.2.5.1 Convert Contexts for Compression Algorithm

This algorithm takes maps state, activeContext, input, and output, and returns a map result containing maps output, state, and activeContext.

  1. Set applyEmbeddedResult to the result of 5.3.2 Apply Embedded Contexts Algorithm, passing state, activeContext, and input.
  2. Set activeContext to applyEmbeddedResult.activeContext and state to applyEmbeddedResult.state.
  3. If "@context" does not have an entry in input:
    1. Set result to an empty map.
    2. Set result.state to state and result.activeContext to activeContext.
    3. Return result.
  4. Set context to the value of "@context" in input.
  5. Set encodedContexts to an empty array.
  6. If context is an array, set isArray to true and contexts to context. Otherwise, set isArray to false and contexts to [context].
  7. For contextValue in contexts:
    1. Set encoderData to the result of 5.5.1.1 Create Context Encoder, passing state.typeTable and contextValue.
    2. If encoderData is an empty map, add contextValue to encodedContexts.
    3. Otherwise, add the value of encoderData to encodedContexts.
  8. If isArray is true, set id to the value of "@context" in state.keywordsMap plus 1 and set the value of id in output to encodedContexts.
  9. Otherwise, set id to the value of "@context" in state.keywordMap and set the value of id in output to the first element of encodedContexts.
  10. Set result.output to output, result.state to state, and result.activeContext to activeContext.
  11. Return result.
5.2.5.2 Convert Value for Compression Algorithm

This algorithm takes maps state and termInfo, and values valueToEncode and termType, and returns a map encoderData.

  1. If valueToEncode is an object, return.
  2. Otherwise, set result to the result of 5.5.2.1 Create Value Encoder, passing state, termInfo, valueToToEncode, and termType.
  3. Return result.
5.2.5.3 Get Input Entries for Compression Algorithm

This algorithm takes maps state, activeContext, and input, and returns a map state and an array entries.

  1. Initialize entries as an empty array.
  2. Set an array keys to the keys of input, sorted lexicographically.
  3. For key in keys:
    1. If key is "@context", continue.
    2. Set value to the value of key in input.
    3. If value is an array, set plural to true. Otherwise, set plural to false.
    4. If key does not have an entry in state.termToId, set termId to key.
    5. Otherwise, if plural is true, set termId to the value of key in state.termToId plus 1.
    6. Otherwise, set termId to the value of key in state.termToId.
    7. If activeContext.termMap has an entry for key, set definition to the value of key in activeContext.termMap. Otherwise, set definition to an empty map.
    8. Set entryTerm to be a new map.
    9. Set the value of "term" in entryTerm to be the value of key. Add termId, plural, and definition to entryTerm.
    10. Create an array entry with two elements, entryTerm and value.
    11. Add entry to entries.
  4. Return a map result containing entries and state.
5.2.5.4 Get Object Types for Compression Algorithm

This algorithm takes maps activeContext and input, and returns a set objectTypes.

  1. Set objectTypes to be an empty set.
  2. For term in activeContext.typeTerms:
    1. If term has an entry in input:
      1. Set types to the value of term in input.
      2. Add each value in types to objectTypes.
  3. Return objectTypes.

5.2.6 Decompression Strategy Algorithms

The algorithms in this section define the "decompression" strategy to be used with the "conversion" algorithms defined previously to convert CBOR-LD to JSON-LD.

5.2.6.1 Convert Contexts for Decompression Algorithm

This algorithm takes maps state, activeContext, input, and output, and returns a map result containing maps output, state, and activeContext.

  1. Set decoderData to the result of 5.5.1.3 Create Context Decoder, passing state.reverseTypeTable.
  2. Set contextTermId to the value of "@context" in state.keywordsMap.
  3. If contextTermId has an entry in input, set the value of "@context" in output to the result of 5.5.1.4 Decode Context, passing decoderData and the value of contextTermId in input as value.
  4. Set contextTermIdPlural to the value of contextTermId plus 1.
  5. If contextTermIdPlural has an entry in input:
    1. If contextTermId also had an entry in input during the previous check, throw an ERR_INVALID_ENCODED_CONTEXT error.
    2. Set encodedContexts to be the value of contextTermIdPlural in input. If encodedContexts is not an array, throw an ERR_INVALID_ENCODED_CONTEXT error.
    3. Set contexts to be an empty array.
    4. For each valueToDecode in encodedContexts, add the result of passing decoderData and valueToDecode as value to 5.5.1.4 Decode Context to contexts.
    5. Set the value of "@context" in output to contexts.
  6. Set embeddedContextResult to the result of 5.3.2 Apply Embedded Contexts Algorithm, passing activeContext, output as input, and state.
  7. Set result to an empty map.
  8. Set result.state to embeddedContextResult.state and result.activeContext to embeddedContextResult.activeContext.
  9. Return result.
5.2.6.2 Convert Value for Decompression Algorithm

This algorithm takes maps state and termInfo, and values termType and valueToDecode, and returns a value decodedValue.

  1. If value is a map, return.
  2. Set decoderData to the result of 5.5.2.3 Create Value Decoder, passing valueToDecode, state, termInfo, and termType.
  3. Set decodedValue to the result of 5.5.2.4 Decode Value, passing decoderData.
  4. Return decodedValue.
5.2.6.3 Get Input Entries for Decompression Algorithm

This algorithm takes maps state, activeContext, and input, and returns a map state and an array entries.

  1. Initialize entries to an empty array.
  2. For key-value pair key and value in input:
    1. If key is the value of "@context" in state.keywordsMap or that value plus 1, continue.
    2. Otherwise, if key is a string, set plural to false and term to key.
    3. Otherwise:
      1. If key is odd, set plural to true. Otherwise, set plural to false.
      2. If plural is true, set term to the value of id minus 1 in state.idToTerm. If that value does not have an entry, throw an error ERR_UNKNOWN_CBORLD_TERM_ID.
      3. Otherwise, set term to the value of id in state.idToTerm. If that value does not have an entry, throw an error ERR_UNKNOWN_CBORLD_TERM_ID.
    4. Set definition to the value of term in activeContext.termMap.
    5. Set entryTerm to be a new map.
    6. Set the value of "termId" in entryTerm to be the value of key. Add term, plural, and definition to entryTerm.
    7. Create an array entry with two elements, entryTerm and value.
    8. Add entry to entries.
  3. Sort entries by the value of term in each element of entries.
  4. Return a map result containing entries and state.
5.2.6.4 Get Object Types for Decompression Algorithm

This algorithm takes maps state, activeContext, input as inputs, and returns a map state and a set objectTypes.

  1. Set objectTypes to be an empty set.
  2. For term in activeContext.typeTerms:
    1. If term does not have an entry in state.termToId, set termId to term.
    2. Otherwise, set termId to the value of term in state.termToId.
    3. If neither termId nor termId plus 1 are present in input, continue.
    4. Otherwise, if termId is present in input, set value to the value of termId in input.
    5. Otherwise, set value to the value of termId plus 1 in input.
    6. If key is a string, set plural to false and term to key.
    7. Otherwise:
      1. If key is odd, set plural to true. Otherwise, set plural to false.
      2. If plural is true, set term to the value of id minus 1 in state.idToTerm. If that value does not have an entry, throw an error ERR_UNKNOWN_CBORLD_TERM_ID.
      3. Otherwise, set term to the value of id in state.idToTerm. If that value does not have an entry, throw an error ERR_UNKNOWN_CBORLD_TERM_ID.
    8. Set definition to the value of term in activeContext.termMap.
    9. Set termInfo to be a new map.
    10. Add term, termId, plural, and definition to termInfo.
    11. If value is not an array, set values to be an array containing as a single element value. Otherwise, set values to the value of value.
    12. For each value in values:
      1. Set decoderData to the result of 5.5.2.3 Create Value Decoder, passing value, termInfo, state, and "@vocab" as termType.
      2. If decoderData exists, add the result of 5.5.2.4 Decode Value, passing decoderData, to `objectTypes.
      3. Otherwise, add value to objectTypes.
  3. Return objectTypes.

5.3 Active Context Processing

The algorithms in this section describe how to determine what components of the context documents associated with a JSON-LD document are in use at any point during compression or decompression. These algorithms include how to apply embedded, type-scoped, and property-scoped contexts with CBOR-LD. This is in contrast to the Context Loading algorithms defined later in this specification, which describe how to construct the mappings from terms to integers that are the core CBOR-LD compression technique. Together, the Active Context Processing and Context Loading algorithms specify how JSON-LD context documents should be processed when converting to and from CBOR-LD.

5.3.1 Initialize Active Context Algorithm

This algorithm takes maps previousActiveContext and termMap, and returns a map activeContext. It updates the active context in use and finds all aliases for '@type'.

  1. Set activeContext to a new map.
  2. Set activeContext.previousActiveContext to previousActiveContext.
  3. Set activeContext.termMap to termMap.
  4. Set activeContext.typeTerms to the array ['@type'].
  5. For [term, def] in termMap:
    1. If the value of "@id" in def is "@type", add term to activeContext.typeTerms.
  6. Return activeContext.

5.3.2 Apply Embedded Contexts Algorithm

This algorithm takes maps state, activeContext, and input as inputs, and returns a map result containing maps state and activeContext.

  1. Set termMapUpdateResult to the result of passing state, activeContext.termMap as activeTermMap, and the value of '@context' in input as contexts to 5.3.5 Update Term Map Algorithm.
  2. Set state to termMapUpdateResult.state.
  3. Set termMap to termMapUpdateResult.activeTermMap.
  4. Set newActiveContext to the result of 5.3.1 Initialize Active Context Algorithm, passing termMap and activeContext as previousActiveContext.
  5. Set result to be a new map, and set result.activeContext to newActiveContext and result.state to state.
  6. Return result.

5.3.3 Apply Property Scoped Contexts Algorithm

This algorithm takes maps state, activeContext, and a string term as inputs and returns a map result containing maps state and activeContext.

  1. Set revertedTermMap to the result of 5.3.6 Revert Term Map Algorithm, passing activeContext.
  2. Set termDef to the value of term in activeContext.termMap. Set contexts to the value of "@context" in termDef.
  3. Set termMapUpdateResult to the result of passing state, revertedTermMap as activeTermMap, true as propertyScope, and contexts to 5.3.5 Update Term Map Algorithm.
  4. Set state to termMapUpdateResult.state.
  5. Set termMap to termMapUpdateResult.activeTermMap.
  6. Set newActiveContext to the result of 5.3.1 Initialize Active Context Algorithm, passing termMap and activeContext as previousActiveContext.
  7. Set result to be a new map, and set result.activeContext to newActiveContext and result.state to state.
  8. Return result.

5.3.4 Apply Type Scoped Contexts Algorithm

This algorithm takes maps state, activeContext ,and a set objectTypes as inputs, and returns a map result containing maps state and activeContext.

  1. Set objectTypesSorted to an empty array.
  2. Lexicographically sort the elements of objectTypes and add the elements to objectTypesSorted in order.
  3. Set newTermMap to activeContext.termMap.
  4. For type in objectTypesSorted:
    1. Set typeDef to the value of type in newTermMap. Set contexts to the value of "@context" in typeDef.
    2. Set termMapUpdateResult to the result of passing state, newTermMap as activeTermMap, contexts, and true as typeScope to 5.3.5 Update Term Map Algorithm.
    3. Set state to termMapUpdateResult.state and newTermMap to termMapUpdateResult.activeTermMap.
  5. Set newActiveContext to the result of 5.3.1 Initialize Active Context Algorithm, passing newTermMap as termMap and activeContext as previousActiveContext.
  6. Set result to be a new map, and set result.activeContext to newActiveContext and result.state to state.
  7. Return result.

5.3.5 Update Term Map Algorithm

This algorithm takes maps state, activeTermMap, and map or array contexts as well as booleans typeScope and propertyScope, both of which default to false if not provided, as inputs. It returns maps state and activeTermMap.

  1. If contexts is not an array, set contexts to be an array with the previous value of contexts as its sole element.
  2. Set allowProtectedOverride to the value of propertyScope.
  3. Set propagateDefault to the negation of the value of typeScope.
  4. For contextIdentifier in contexts:
    1. Set loadResult to the result of 5.4.2 Load Context Algorithm, passing state and contextIdentifier.
    2. Set entry to loadResult.entry, context to entry.context, and state to loadResult.state.
    3. If @propagate appears in context, set propagate to the value of @propagate in context. Otherwise, set propagate to the value of propagateDefault.
    4. Set newTermMap to be an empty map. For [key, value] in entry.termMap:
      1. Shallow copy the contents of value into a new map newValue and add propagate to newValue.
      2. Set the value of key in newTermMap to newValue.
    5. For [term, activeDef] in activeTermMap:
      1. Let def be the value of term in newTermMap.
      2. If def is defined:
        1. If the value of protected in activeDef is true:
          1. If allowProtectedOverride is set to false and def is not identical to activeDef, throw an error ERR_PROTECTED_TERM_REDEFINITION.
          2. Otherwise, set the value of term in newTermMap to a map containing the values from activeDef and propagate set to the value of def.propagate.
      3. Otherwise, if term appears in context, set the value of term in newTermMap to a map containing all values from activeDef.
    6. Set the value of activeTermMap to the value of newTermMap.
  5. Set result to be an empty map.
  6. Set result.state to state and result.activeTermMap to activeTermMap.
  7. Return result.

5.3.6 Revert Term Map Algorithm

This algorithm takes as input a map activeContext, and returns a map newTermMap.

  1. Set newTermMap to an empty map.
  2. Set nonPropagatingTerms to an empty array.
  3. For [term, def] in activeContext:
    1. If def.propagate is set to false, add term to nonPropagatingTerms and proceed to the next iteration of this loop.
    2. Otherwise, set the value of term in newTermMap to def.
  4. For term in nonPropagatingTerms:
    1. Set currentContext to activeContext.previousActiveContext.
    2. Set def to the value of term in currentContext.termMap.
    3. While def is not undefined and def.propagate is set to false:
      1. Set currentContext to activeContext.previousActiveContext.
      2. Set def to the value of term in currentContext.termMap.
    4. If def is not undefined, set the value of term in newTermMap to def.
  5. Return newTermMap.

5.4 Context Loading

The algorithms in this section define how to construct the mappings between terms and integers that are used as the core CBOR-LD compression technique.

5.4.1 Initialize Context Loader Algorithm

This algorithm takes and returns a map state.

  1. Set state.contextMap to a new map.
  2. Set state.nextTermId to 100.
  3. Set state.keywordsMap to the following map of JSON-LD keywords to their associated integer values:
    {
      '@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,
      '@propagate' => 54
    }
  4. Add each entry in state.keywordsMap to state.termToId.
  5. If state.strategy is set to "decompression", set state.idToTerm to the reverse map of state.termToId (i.e., a map from integers to JSON-LD keywords).
  6. Return state.

5.4.2 Load Context Algorithm

This algorithm takes a map state and a context map or URL contextIdentifier, and returns result, a map containing maps state and entry.

  1. If state.contextMap has an entry for contextIdentifier:
    1. Initialize result to an empty map.
    2. Set result.state to state.
    3. Set result.entry to the value of contextIdentifier in state.contextMap.
    4. Return result.
  2. If context is a string:
    1. Fetch the associated context object and set context to the value of "@context" in that object.
    2. Set contextUrl to the value of contextIdentifier.
  3. Otherwise, set context to contextIdentifier.
  4. Set result to the result of 5.4.3 Add Context Algorithm, passing state, context, and contextUrl if set.
  5. Return result.

5.4.3 Add Context Algorithm

This algorithm takes a map state, a context object context, and a context URL contextUrl, and returns result, a map containing maps state and entry.

  1. If context has an entry "@import":
    1. Set importUrl to the value of "@import" in `context.
    2. If state.contextMap does not have an entry for importUrl:
      1. Fetch the context object associated with importUrl and set importContext to the value of "@context" in that object.
      2. Set importedContextAdditionResult to the result of 5.4.3 Add Context Algorithm, passing state, importContext as context, and importUrl as contextUrl.
      3. Set state to importedContextAdditionResult.state and importEntry to importedContextAdditionResult.entry.
    3. Otherwise, set importEntry to the value of importUrl in state.contextMap.
    4. Set context to a map containing all entries from context as well as importEntry.context.
  2. Set termMap to an empty map.
  3. Set entry to be an object containing context and termMap.
  4. Set sortedTerms to the result of sorting the keys in context in lexicographic order.
  5. Set isProtected to true if "@protected" has an entry in context and false otherwise.
  6. For term in sortedTerms:
    1. If term has an entry in state.keywordsMap, proceed to the next iteration of this loop.
    2. Set definition to the value of term in context.
    3. If definition is null, proceed to the next iteration of this loop.
    4. If definition is a string:
      1. Set newDefinition to an empty map.
      2. Set the value of "@id" in newDefinition to definition.
      3. Set the value of definition to newDefinition.
    5. Set the value of protected in definition to isProtected.
    6. Set the value of term in termMap to definition.
    7. If term does not have an entry in state.termToId:
      1. Set termId to state.nextTermId.
      2. Increment state.nextTermId by 2.
      3. Set the value of term in state.termToId to termId.
      4. Set the value of termId in state.idToTerm to term.
  7. If contextUrl is defined, set the value of contextUrl in state.contextMap to entry.
  8. Otherwise, set the value of context in state.contextMap to entry.
  9. Set result to be an empty map.
  10. Set result.state to state and result.entry to entry.
  11. Return result.

5.5 Codecs

The codecs in this section specify exactly how individual values in JSON-LD should be converted to CBOR and vice versa. They are used by the algorithms in the previous section, and allow CBOR-LD to efficiently encode both primitive and non-primitive types as CBOR.

5.5.1 Context Codec

5.5.1.1 Create Context Encoder

This algorithm takes a map typeTable and a value contextValue and returns a map encoderData.

  1. Initialize encoderData to an empty map.
  2. If contextValue is not a string, return.
  3. Otherwise, set contextTable to the value of "context" in typeTable.
  4. Set encoderData.context to contextValue and encoderData.contextTable to contextTable.
  5. Return encoderData.
5.5.1.2 Encode Context

This algorithm takes a map encoderData, and returns CBOR binary data.

  1. If encoderData.context has an entry in encoderData.contextTable, return a CBOR encoding of the value of encoderData.context in encoderData as a Major Type 0 (unsigned integer) object.
  2. Otherwise, return a CBOR encoding of the value of encoderData.context as a Major Type 3 (text string) object.
5.5.1.3 Create Context Decoder

This algorithm takes a map reverseTypeTable, and returns a map encoderData.

  1. Set reverseContextTable to the value of "context" in reverseTypeTable.
  2. Initialize decoderData to an empty map.
  3. Set decoderData.reverseContextTable to the value of reverseContextTable and return decoderData.
5.5.1.4 Decode Context

This algorithm takes a map decoderData and a value value, and returns a value.

  1. If value is not a number, return value.
  2. Otherwise, if decoderData.reverseContextTable has an entry for value, return the value of that entry.
  3. Otherwise, throw an error ERR_UNDEFINED_COMPRESSED_CONTEXT.

5.5.2 Value Codec

5.5.2.1 Create Value Encoder

This algorithm takes maps state and termInfo, and values termType and valueToEncode, and returns a map encoderData or valueToEncode.

  1. Set isUrl to false.
  2. If termInfo.term is "@id" or "@type", set isUrl to true.
  3. If the value of "@id" in termInfo.def is "@id" or "@type", set isUrl to true.
  4. If termType is "@id" or "@vocab", set isUrl to true.
  5. If isUrl is true, set tableType to "url".
  6. Otherwise, if termType is defined, set tableType to termType.
  7. Otherwise, set tableType to "none".
  8. If state.typeTable has an entry for tableType:
    1. Set subTable to the value of tableType in state.typeTable.
    2. If subTable has an entry for valueToEncode:
      1. Set intValue to the value of valueToEncode in subTable. Set includeSign to false.
      2. If state.typesEncodedAsBytes has an entry for tableType, set convertToBytes to true. Otherwise, set convertToBytes to false.
    3. Otherwise, if tableType is not "none" and valueToEncode is an integer:
      1. Set intValue to the value of valueToEncode.
      2. Set convertToBytes and includeSign to true.
    4. If intValue is defined:
      1. Initialize encoderData to an empty map.
      2. Set encoderData.intValue to the value of intValue, encoderData.convertToBytes to the value of convertToBytes, and encoderData.includeSign to the value of includeSign.
      3. Return encoderData.
  9. If tableType has an entry in state.processingModeTypeEncoders, set encoderData to the result of calling the Create Encoder algorithm associated with that entry's codec.
  10. If encoderData is defined, return encoderData.
  11. Return valueToEncode.
5.5.2.2 Encode Value

This algorithm takes a map encoderData, and returns CBOR binary data.

  1. If encoderData.convertToBytes is true:
    1. Set bytes to the result of converting intValue to bytes, using the value of includeSign to determine whether the binary representation of the integer should be signed or unsigned.
    2. Return a CBOR encoding of bytes as a Major Type 2 (byte string) object.
  2. Otherwise, return a CBOR encoding of intValue as a Major Type 0 (unsigned integer) object.
5.5.2.3 Create Value Decoder

This algorithm takes maps state and termInfo, and values termType and valueToDecode, and returns a map decoderData.

  1. Set isUrl to false.
  2. If termInfo.term is "@id" or "@type", set isUrl to true.
  3. If the value of "@id" in termInfo.def is "@id" or "@type", set isUrl to true.
  4. If termType is "@id" or "@vocab", set isUrl to true.
  5. If isUrl is true, set tableType to "url".
  6. Otherwise, if termType is defined, set tableType to termType.
  7. Otherwise, set tableType to "none".
  8. If state.reverseTypeTable has an entry for tableType:
    1. Set subTable to the value of tableType in state.reverseTypeTable.
    2. Set useTable to false.
    3. If valueToDecode is a byte array and state.typesEncodedAsBytes has an entry for tableType:
      1. Set useTable to true.
      2. Set intValue to the unsigned integer conversion of the valueToDecode bytes.
    4. Otherwise, if valueToDecode is an integer and state.typesEncodedAsBytes does not have an entry for tableType:
      1. Set useTable to true.
      2. Set intValue to valueToDecode.
    5. If useTable is true:
      1. If intValue is not in subTable, throw an error ERR_UNKNOWN_COMPRESSED_VALUE.
      2. Otherwise, set decoded to the value of intValue in subTable.
    6. Otherwise, if valueToDecode is a byte array and tableType is not "none", set decoded to the integer conversion of valueToDecode.
    7. If decoded is defined, initialize decoderData to an empty map, set decoderData.decoded to the value of decoded, and return decoderData.
  9. If tableType has an entry in state.processingModeTypeDecoders, set DecoderData to the result of calling the Create Decoder algorithm associated with that entry's codec.
  10. If decoderData is defined, return decoderData.
  11. Otherwise, if valueToDecode is not an array, initialize decoderData to an empty map, set decoderData.decoded to valueToDecode, and return decoderData.
5.5.2.4 Decode Value

This algorithm takes a map decoderData, and returns a value.

  1. Return decoderData.decoded.

5.5.3 URL Codec

The URL Codec compresses URL values based on the scheme of the value. URLs are encoded as arrays, where the first integer denotes the scheme of the URL. The codec first checks whether the value matches a known JSON-LD term identifier, encoding it as a simple integer if so. Otherwise it delegates to one of the following URI-scheme-specific sub-codecs based on the URI scheme of the value.

5.5.3.1 URL Scheme Table

The URL Scheme Table maps URI scheme prefixes to their associated compressed integer identifiers. Implementations that use the URL codec MUST use the following table. The URL Scheme Reverse Table is the inversion of this table (i.e. a map from integer to scheme prefix string).

URI Scheme PrefixInteger Identifier
http://1
https://2
urn:uuid:3
data:4
did:v1:nym:1024
did:key:1025
5.5.3.2 Create URL Encoder

This algorithm takes maps state, termInfo, and a string valueToEncode, and returns an encoder object or undefined.

  1. If valueToEncode is not a string, throw an ERR_UNSUPPORTED_JSON_TYPE error.
  2. Set termId to the result of looking up valueToEncode in state.termToId.
  3. If termId is an integer, return an encoder that, when invoked via 5.5.3.3 Encode URL, encodes termId as a Major Type 0 (unsigned integer) CBOR item.
  4. Attempt to parse the URI scheme from valueToEncode. If parsing fails (the value is not a valid URI), return undefined.
  5. Set scheme to the longest matching prefix of valueToEncode that appears in the URL Scheme Table.
  6. If scheme starts with "https" or "http", return the result of 5.5.3.6.1 Create HTTP URL Encoder passing valueToEncode and scheme.
  7. If scheme is "urn:uuid", return the result of 5.5.3.7.1 Create UUID URN Encoder passing valueToEncode.
  8. If scheme is "data", return the result of 5.5.3.8.1 Create Data URL Encoder passing valueToEncode.
  9. If scheme is "did:v1:nym" or "did:key", return the result of 5.5.3.9.1 Create Base58 DID URL Encoder passing valueToEncode and scheme.
  10. Return undefined (no compression possible for this URI).
5.5.3.3 Encode URL

This algorithm takes an encoder object produced by 5.5.3.2 Create URL Encoder, and returns CBOR binary data.

  1. If the encoder was created for a term-ID match (step 3 of 5.5.3.2 Create URL Encoder), return a CBOR encoding of termId as a Major Type 0 (unsigned integer) object.
  2. Otherwise, invoke the encode method of the appropriate URI-scheme sub-encoder and return the resulting CBOR binary data.
5.5.3.4 Create URL Decoder

This algorithm takes maps state, termInfo, and a value valueToDecode, and returns a decoder object or undefined.

  1. If valueToDecode is a string, return undefined (value is already an uncompressed URL string; pass through).
  2. If valueToDecode is an array:
    1. Set schemeId to the first element of valueToDecode.
    2. Set scheme to the value of schemeId in the URL Scheme Reverse Table.
    3. If scheme is "http://" or "https://", return the result of 5.5.3.6.3 Create HTTP URL Decoder passing valueToDecode.
    4. If scheme is "urn:uuid:", return the result of 5.5.3.7.3 Create UUID URN Decoder passing valueToDecode.
    5. If scheme is "data:", return the result of 5.5.3.8.3 Create Data URL Decoder passing valueToDecode.
    6. If scheme is "did:v1:nym:" or "did:key:", return the result of 5.5.3.9.4 Create Base58 DID URL Decoder passing valueToDecode.
    7. Otherwise, throw an ERR_UNKNOWN_COMPRESSED_VALUE error.
  3. If valueToDecode is an integer, set term to the result of looking up valueToDecode in state.idToTerm and return a decoder whose 5.5.3.5 Decode URL invocation returns term.
  4. Return undefined.
5.5.3.5 Decode URL

This algorithm takes a decoder object produced by 5.5.3.4 Create URL Decoder, and returns a string value.

  1. If the decoder was created for an integer term-ID value (step 3 of 5.5.3.4 Create URL Decoder), return the associated term string.
  2. Otherwise, invoke the decode method of the appropriate URI-scheme sub-decoder and return the resulting string.
5.5.3.6 HTTP URL Codec

The HTTP URL Codec handles values whose URI scheme is http:// or https://. An encoded HTTP URL is represented as a two-element CBOR array [schemeId, remainder] where schemeId is the integer from the URL Scheme Table and remainder is the scheme-stripped portion of the URL as a text string.

5.5.3.6.1 Create HTTP URL Encoder

This algorithm takes a string value and a string scheme (either "https://" or "http://"), and returns an encoder object or undefined.

  1. If value starts with "https://", set scheme to "https://".
  2. Otherwise, if value starts with "http://", set scheme to "http://".
  3. Otherwise, return undefined.
  4. Return an encoder object containing value and scheme.
5.5.3.6.2 Encode HTTP URL

This algorithm takes an encoder object from 5.5.3.6.1 Create HTTP URL Encoder, and returns CBOR binary data.

  1. Set schemeId to the value of encoderData.scheme in the URL Scheme Table.
  2. Set rest to the substring of encoderData.value beginning after encoderData.scheme.
  3. Return a CBOR encoding of a two-element array [schemeId, rest]: Major Type 4 (array) containing a Major Type 0 (unsigned integer) item followed by a Major Type 3 (text string) item.
5.5.3.6.3 Create HTTP URL Decoder

This algorithm takes a CBOR array valueToDecode, and returns a decoder object or undefined.

  1. If valueToDecode has exactly two elements and the second element is a text string:
    1. Set scheme to the value of valueToDecode[0] in the URL Scheme Reverse Table.
    2. Return a decoder object containing scheme.
  2. Otherwise, return undefined.
5.5.3.6.4 Decode HTTP URL

This algorithm takes a decoder object from 5.5.3.6.3 Create HTTP URL Decoder and a CBOR array valueToDecode, and returns a string.

  1. Return the concatenation of decoderData.scheme and valueToDecode[1].
5.5.3.7 UUID URN Codec

The UUID URN Codec handles values whose URI scheme is urn:uuid:. An encoded UUID URN is a two-element CBOR array [3, uuidValue] where uuidValue is either a 16-byte Major Type 2 (byte string) representing the UUID in binary form (when the UUID string is all lowercase), or a Major Type 3 (text string) containing the UUID value verbatim (when the casing cannot be round-tripped through binary form).

5.5.3.7.1 Create UUID URN Encoder

This algorithm takes a string value, and returns an encoder object or undefined.

  1. If value does not start with "urn:uuid:", return undefined.
  2. Return an encoder object containing value.
5.5.3.7.2 Encode UUID URN

This algorithm takes an encoder object, and returns CBOR binary data.

  1. Set schemeId to 3 (the entry for "urn:uuid:" in the URL Scheme Table).
  2. Set rest to the substring of encoderData.value beginning after "urn:uuid:".
  3. If rest is entirely lowercase:
    1. Set uuidBytes to the 16-byte binary representation of the UUID obtained by parsing rest according to [RFC4122].
    2. Return a CBOR encoding of a two-element array [3, uuidBytes]: Major Type 4 (array) containing a Major Type 0 (unsigned integer) item followed by a Major Type 2 (byte string) item of length 16.
  4. Otherwise, return a CBOR encoding of a two-element array [3, rest]: Major Type 4 (array) containing a Major Type 0 (unsigned integer) item followed by a Major Type 3 (text string) item.
5.5.3.7.3 Create UUID URN Decoder

This algorithm takes a CBOR array valueToDecode, and returns a decoder object or undefined.

  1. If valueToDecode has exactly two elements, and the second element is either a byte string or a text string, return a decoder object.
  2. Otherwise, return undefined.
5.5.3.7.4 Decode UUID URN

This algorithm takes a decoder object and a CBOR array valueToDecode, and returns a string.

  1. If valueToDecode[1] is a text string, set uuid to valueToDecode[1].
  2. Otherwise, set uuid to the UUID string representation of the 16-byte binary value valueToDecode[1] per [RFC4122] (lowercase, hyphen-delimited form).
  3. Return the concatenation of "urn:uuid:" and uuid.
5.5.3.8 Data URL Codec

The Data URL Codec handles values whose URI scheme is data:, as defined in [RFC2397]. Base64-encoded data URLs (matching data:<mediatype>;base64,<data>) are encoded as a three-element CBOR array [4, mediatype, dataBytes]. Non-base64 data URLs are encoded as a two-element CBOR array [4, rest] where rest is the portion of the URL after "data:".

5.5.3.8.1 Create Data URL Encoder

This algorithm takes a string value, and returns an encoder object or undefined.

  1. If value does not start with "data:", return undefined.
  2. Attempt to match value against the pattern data:(?<mediatype>.*);base64,(?<data>.*).
  3. If the match succeeds:
    1. Set data to the value of the data capture group.
    2. Verify round-trip integrity: decode data from base64 and re-encode to base64. If the result equals data, return an encoder object with value and base64 set to true.
  4. Return an encoder object with value and base64 set to false.
5.5.3.8.2 Encode Data URL

This algorithm takes an encoder object from 5.5.3.8.1 Create Data URL Encoder, and returns CBOR binary data.

  1. Set schemeId to 4 (the entry for "data:" in the URL Scheme Table).
  2. If encoderData.base64 is true:
    1. Parse encoderData.value to extract mediatype (the substring between "data:" and ";base64,") and dataBytes (the binary decoding of the base64 data portion).
    2. Return a CBOR encoding of a three-element array [schemeId, mediatype, dataBytes]: Major Type 4 (array) containing a Major Type 0 integer, a Major Type 3 text string, and a Major Type 2 byte string.
  3. Otherwise:
    1. Set rest to the substring of encoderData.value beginning after "data:".
    2. Return a CBOR encoding of a two-element array [schemeId, rest]: Major Type 4 (array) containing a Major Type 0 integer and a Major Type 3 text string.
5.5.3.8.3 Create Data URL Decoder

This algorithm takes a CBOR array valueToDecode, and returns a decoder object or undefined.

  1. If valueToDecode has exactly three elements, the second element is a text string, and the third element is a byte string, return a decoder object (base64 mode).
  2. Otherwise, if valueToDecode has exactly two elements and the second element is a text string, return a decoder object (non-base64 mode).
  3. Otherwise, return undefined.
5.5.3.8.4 Decode Data URL

This algorithm takes a decoder object and a CBOR array valueToDecode, and returns a string.

  1. If valueToDecode has three elements (base64 mode):
    1. Set mediatype to valueToDecode[1].
    2. Set encodedData to the base64 encoding of the byte string valueToDecode[2].
    3. Return the concatenation of "data:", mediatype, ";base64,", and encodedData.
  2. Otherwise (non-base64 mode), return the concatenation of "data:" and valueToDecode[1].
5.5.3.9 Base58 DID URL Codec

The Base58 DID URL Codec handles DID URLs using the did:v1:nym: and did:key: schemes, whose authority (and optional fragment) components are typically multibase base58btc-encoded strings (those starting with the character 'z'). A compressed DID URL is encoded as a two- or three-element CBOR array [schemeId, authority] or [schemeId, authority, fragment]. When a component starts with 'z' and is valid base58btc, it is stored as a raw byte string; otherwise it is stored as a text string.

Note
5.5.3.9.1 Create Base58 DID URL Encoder

This algorithm takes a string value and a string scheme, and returns an encoder object or undefined.

  1. For each [scheme, schemeId] pair in the URL Scheme Table where the scheme starts with "did:":
    1. If value starts with scheme, return an encoder object containing value, scheme, and schemeId.
  2. Return undefined.
5.5.3.9.2 Encode Base58 DID URL

This algorithm takes an encoder object from 5.5.3.9.1 Create Base58 DID URL Encoder, and returns CBOR binary data.

  1. Set suffix to the substring of encoderData.value beginning after encoderData.scheme.
  2. Split suffix on the first occurrence of '#' to produce authority and, if present, fragment.
  3. Set authorityEncoded to the result of applying the Multibase Base58 to CBOR Token algorithm to authority.
  4. Initialize entries to [encoderData.schemeId, authorityEncoded].
  5. If fragment is defined:
    1. Set fragmentEncoded to the result of applying the Multibase Base58 to CBOR Token algorithm to fragment.
    2. Append fragmentEncoded to entries.
  6. Return a CBOR encoding of entries as a Major Type 4 (array).
5.5.3.9.3 Multibase Base58 to CBOR Token

The Multibase Base58 to CBOR Token algorithm takes a string str and returns either a Major Type 2 (byte string) CBOR token (if the value is a base58btc multibase string) or a Major Type 3 (text string) CBOR token.

  1. If str starts with 'z':
    1. Set decoded to the result of decoding the base58btc content of str (i.e. str[1:]).
    2. If decoding succeeds, return a Major Type 2 (byte string) CBOR token for decoded.
  2. Return a Major Type 3 (text string) CBOR token for str.
5.5.3.9.4 Create Base58 DID URL Decoder

This algorithm takes a CBOR array valueToDecode, and returns a decoder object or undefined.

  1. If valueToDecode has exactly two or three elements:
    1. Set prefix to the value of valueToDecode[0] in the URL Scheme Reverse Table.
    2. Return a decoder object containing prefix.
  2. Otherwise, return undefined.
5.5.3.9.5 Decode Base58 DID URL

This algorithm takes a decoder object from 5.5.3.9.4 Create Base58 DID URL Decoder and a CBOR array valueToDecode, and returns a string.

  1. Set url to decoderData.prefix.
  2. If valueToDecode[1] is a byte string, append 'z' followed by the base58btc encoding of valueToDecode[1] to url.
  3. Otherwise, append valueToDecode[1] to url.
  4. If valueToDecode has more than two elements:
    1. If valueToDecode[2] is a byte string, append "#z" followed by the base58btc encoding of valueToDecode[2] to url.
    2. Otherwise, append "#" followed by valueToDecode[2] to url.
  5. Return url.

5.5.4 XSD Date Codec

The XSD Date Codec compresses values whose type is http://www.w3.org/2001/XMLSchema#date. A date value is represented as an integer count of seconds since the Unix epoch (1970-01-01T00:00:00Z), encoded as a CBOR Major Type 0 (unsigned integer) for non-negative values or Major Type 1 (negative integer) for dates before the epoch. The codec only compresses date strings that exactly round-trip through this representation; otherwise the original string is retained verbatim.

Note
5.5.4.1 Create XSD Date Encoder

This algorithm takes a string value, and returns an encoder object or undefined.

  1. If value contains the character 'T' (indicating a time component), return undefined (this value is compressed instead by the XSD DateTime Codec).
  2. Set parsed to the result of parsing value as an ISO 8601 date string, expressed as the number of milliseconds since the Unix epoch.
  3. If parsed is not a valid number, return undefined.
  4. Return an encoder object containing value and parsed.
5.5.4.2 Encode XSD Date

This algorithm takes an encoder object from 5.5.4.1 Create XSD Date Encoder, and returns CBOR binary data.

  1. Set secondsSinceEpoch to floor(encoderData.parsed / 1000).
  2. Set reconstituted to the ISO 8601 string for the instant secondsSinceEpoch × 1000 milliseconds since the Unix epoch.
  3. Set expectedDate to the substring of reconstituted preceding the first occurrence of 'T'.
  4. If encoderData.value is not equal to expectedDate, the compression would be lossy. Return a CBOR encoding of encoderData.value as a Major Type 3 (text string) object.
  5. If secondsSinceEpoch is greater than or equal to 0, return a CBOR encoding of secondsSinceEpoch as a Major Type 0 (unsigned integer) object.
  6. Otherwise, return a CBOR encoding of secondsSinceEpoch as a Major Type 1 (negative integer) object.
5.5.4.3 Create XSD Date Decoder

This algorithm takes a value valueToDecode, and returns a decoder object or undefined.

  1. If valueToDecode is an integer (positive, negative, or zero), return a decoder object.
  2. Otherwise, return undefined.
5.5.4.4 Decode XSD Date

This algorithm takes a decoder object and an integer value value, and returns a string.

  1. Set dateString to the ISO 8601 string for the instant value * 1000 milliseconds since the Unix epoch.
  2. Return the substring of dateString preceding the first occurrence of 'T'.

5.5.5 XSD DateTime Codec

The XSD DateTime Codec compresses values whose type is http://www.w3.org/2001/XMLSchema#dateTime. Second-precision datetime values are encoded as a single integer count of seconds since the Unix epoch (Major Type 0 or 1). Sub-second-precision datetime values are encoded as a two-element CBOR array [seconds, milliseconds], both as Major Type 0 integers. As with the XSD Date Codec, the value is only compressed if the compression is lossless (the original string round-trips through the encoding exactly).

5.5.5.1 Create XSD DateTime Encoder

This algorithm takes a string value, and returns an encoder object or undefined.

  1. If value does not contain the character 'T', return undefined (this value is compressed instead by the XSD Date Codec).
  2. Set parsed to the result of parsing value as an ISO 8601 datetime string, expressed as the number of milliseconds since the Unix epoch.
  3. If parsed is not a valid number, return undefined.
  4. Return an encoder object containing value and parsed.
5.5.5.2 Encode XSD DateTime

This algorithm takes an encoder object from 5.5.5.1 Create XSD DateTime Encoder, and returns CBOR binary data.

  1. Set secondsSinceEpoch to floor(encoderData.parsed / 1000).
  2. If encoderData.value does not contain the character '.' (no millisecond component):
    1. Set expectedDate to the ISO 8601 string for the instant secondsSinceEpoch * 1000 milliseconds since the Unix epoch, with the substring ".000Z" replaced by "Z".
    2. If encoderData.value is not equal to expectedDate, the compression would be lossy. Return a CBOR encoding of encoderData.value as a Major Type 3 (text string) object.
    3. If secondsSinceEpoch is greater than or equal to 0, return a CBOR encoding of secondsSinceEpoch as a Major Type 0 (unsigned integer) object.
    4. Otherwise, return a CBOR encoding of secondsSinceEpoch as a Major Type 1 (negative integer) object.
  3. Otherwise (millisecond component is present):
    1. Set millisecondIndex to the index of the first '.' in encoderData.value.
    2. Set milliseconds to the integer value of the digits of encoderData.value beginning at position millisecondIndex + 1.
    3. Set expectedDate to the ISO 8601 string for the instant secondsSinceEpoch * 1000 + milliseconds milliseconds since the Unix epoch.
    4. If encoderData.value is not equal to expectedDate, the compression would be lossy. Return a CBOR encoding of encoderData.value as a Major Type 3 (text string) object.
    5. Return a CBOR encoding of the two-element array [secondsSinceEpoch, milliseconds]: Major Type 4 (array) containing two Major Type 0 (unsigned integer) items.
5.5.5.3 Create XSD DateTime Decoder

This algorithm takes a value valueToDecode, and returns a decoder object or undefined.

  1. If valueToDecode is an integer, return a decoder object.
  2. If valueToDecode is an array of exactly two elements where both elements are numbers, return a decoder object.
  3. Otherwise, return undefined.
5.5.5.4 Decode XSD DateTime

This algorithm takes a decoder object and a value value (either an integer or a two-element array of integers), and returns a string.

  1. If value is an integer:
    1. Set instantMs to value * 1000.
    2. Set dateString to the ISO 8601 string for the instant instantMs milliseconds since the Unix epoch.
    3. Return dateString with the substring ".000Z" replaced by "Z".
  2. Otherwise (value is a two-element array):
    1. Set instantMs to value[0] * 1000 + value[1].
    2. Return instantMs.

5.5.6 Multibase Codec

The Multibase Codec compresses values whose type is https://w3id.org/security#multibase. A multibase-encoded string is converted to a raw byte string whose first byte is the Multibase Prefix Byte and whose remaining bytes are the decoded binary payload. This allows the binary payload to be stored compactly without the overhead of the base-encoding characters.

The following multibase encodings are supported:

Multibase Prefix Character Multibase Prefix Byte Encoding
z 0x7a Base58btc
u 0x75 Base64url (no padding)
M 0x4d Base64pad
5.5.6.1 Create Multibase Encoder

This algorithm takes a value value, and returns an encoder object or undefined.

  1. If value is not a string, return undefined.
  2. If the first character of value is 'z', 'u', or 'M', return an encoder object containing value.
  3. Otherwise, return undefined (unsupported multibase encoding).
5.5.6.2 Encode Multibase

This algorithm takes an encoder object from 5.5.6.1 Create Multibase Encoder, and returns CBOR binary data.

  1. Set prefixChar to the first character of encoderData.value.
  2. Set prefixByte to the Multibase Prefix Byte corresponding to prefixChar.
  3. Set content to the substring of encoderData.value beginning after the first character.
  4. If prefixChar is 'z', set suffixBytes to the base58btc decoding of content.
  5. Otherwise, if prefixChar is 'u', set suffixBytes to the base64url decoding of content.
  6. Otherwise (prefixChar is 'M'), set suffixBytes to the base64pad decoding of content.
  7. Set bytes to a byte array of length 1 + length(suffixBytes), with the first byte set to prefixByte and the remaining bytes set to suffixBytes.
  8. Return a CBOR encoding of bytes as a Major Type 2 (byte string) object.
5.5.6.3 Create Multibase Decoder

This algorithm takes a value valueToDecode, and returns a decoder object or undefined.

  1. If valueToDecode is not a byte string, return undefined.
  2. If the first byte of valueToDecode is 0x7a, 0x75, or 0x4d, return a decoder object.
  3. Otherwise, return undefined (unsupported multibase prefix byte).
5.5.6.4 Decode Multibase

This algorithm takes a decoder object and a byte string value, and returns a string.

  1. Set prefixByte to the first byte of value.
  2. Set suffix to the remaining bytes of value (i.e., all bytes after the first).
  3. If prefixByte is 0x7a ('z'):
    1. Return the concatenation of "z" and the base58btc encoding of suffix.
  4. If prefixByte is 0x75 ('u'):
    1. Return the concatenation of "u" and the base64url encoding (no padding) of suffix.
  5. If prefixByte is 0x4d ('M'):
    1. Return the concatenation of "M" and the base64pad encoding of suffix.
  6. Otherwise, return value.

5.6 CBOR Tag Processing

5.6.1 Get CBOR Tag Structure Algorithm

This algorithm takes as input an integer registryEntryId, and returns a byte string prefix.
  1. Set registryEntryBytes to the CBOR encoding of registryEntryID
  2. Set prefix to the result of appending registryEntryBytes to the end of the bytestring 0xD9CB1D82.
  3. Return prefix.

5.6.2 Get Registry Entry ID Algorithm

This algorithm takes an encoded CBOR-LD payload cborldBytes as input, and returns suffix, the main data to be decoded, as well as the registryEntryId value that should be used to decompress suffix.

  1. If the CBOR tag on cborldbytes is not 0xCB1D (tag value 51997), throw an ERR_NON_CBOR_LD_TAG error.
  2. If the tagged item is not an array of two elements where the first is a CBOR integer, throw an ERR_INVALID_PAYLOAD_STRUCTURE error.
  3. Set the value of registryEntryId to the value of the integer at index 0 of the tagged array.
  4. Set the value of suffix to the value of the second element of the array.
  5. Set result to be an empty map.
  6. Set result.suffix to the value of suffix and result.registryEntryId to the value of registryEntryId.
  7. Return result.

6. Security Considerations

This section is non-normative.

7. Privacy Considerations

This section is non-normative.

8. IANA Considerations

This section is non-normative.

8.1 CBOR Tag

This specification registers a CBOR tag to allow consumers to identify CBOR-LD payloads. The following is provisional, and has not yet been ratified by IANA.

Tag: 51997

Registry: https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml

Data item: array

Semantics: a tag value of 51997 indicates that the payload is CBOR-LD.

Description of semantics: https://w3c.github.io/cbor-ld/#cbor-tags-for-cbor-ld

Point of contact: Wesley Smith (wsmith@digitalbazaar.com)

A. References

A.1 Normative references

[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/
[RFC2397]
The "data" URL scheme. L. Masinter. IETF. August 1998. Proposed Standard. URL: https://www.rfc-editor.org/info/rfc2397/
[RFC4122]
A Universally Unique IDentifier (UUID) URN Namespace. P. Leach; M. Mealling; R. Salz. IETF. July 2005. Proposed Standard. URL: https://www.rfc-editor.org/info/rfc4122/
[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/