RFC 8746
Concise Binary Object Representation (CBOR) Tags for Typed Arrays
RFC 8746: CBOR Tags for Typed Arrays ๐
Okay bestie, let's get into it. RFC 8746 is titled Concise Binary Object Representation (CBOR) Tags for Typed Arrays ๐. It was written by C. Bormann, Ed. from Universitรคt Bremen TZI and published in February 2020. It's on the Standards Track (so it's a real, official Internet standard ๐), and its ISSN is 2070-1721. The title block doesn't list anything it obsoletes or updates, so it's a standalone document โจ.
Abstract โจ
So CBOR is the Concise Binary Object Representation, defined in RFC 7049 ๐ฆ. Its design goals include the possibility of extremely small code size, fairly small message size, and extensibility without the need for version negotiation. Literally built different ๐ .
This doc uses that extensibility to define a bunch of CBOR tags for typed arrays of numeric data ๐ฅ. It also adds more tags for multi-dimensional and homogeneous arrays ๐. It's meant to be the reference doc for the IANA registration of the CBOR tags it defines ๐.
Status of This Memo ๐ธ
This is an Internet Standards Track document. It's a product of the Internet Engineering Task Force (IETF), which means it represents the consensus of the IETF community ๐ซถ. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check out Section 2 of RFC 7841 ๐.
Info about the current status of this doc, any errata, and how to give feedback is at https://www.rfc-editor.org/info/rfc8746 ๐ง.
Copyright Notice ๐
Copyright (c) 2020 IETF Trust and the persons identified as the document authors. All rights reserved ๐ฆ.
This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as in effect on the date of publication. Please actually read these, because they describe your rights and restrictions for this document ๐. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they're provided without warranty as described in the Simplified BSD License โ ๏ธ.
Table of Contents ๐
1. Introduction
1.1. Terminology
2. Typed Arrays
2.1. Types of Numbers
3. Additional Array Tags
3.1. Multi-dimensional Array
3.1.1. Row-Major Order
3.1.2. Column-Major Order
3.2. Homogeneous Array
4. Discussion
5. CDDL Typenames
6. IANA Considerations
7. Security Considerations
8. References
8.1. Normative References
8.2. Informative References
Acknowledgements
Contributors
Author's Address
1. Introduction โจ
Okay so CBOR (that's [RFC7049]) lets you interchange structured data without needing a pre-agreed schema ๐ธ. [RFC7049] defines a basic set of data types, plus a tagging mechanism that lets you extend the set of data types through an IANA registry ๐ง.
Recently, a simple form of typed arrays of numeric data has been getting a LOT of love from the Web graphics community [TypedArray] and from the JavaScript spec (see Section 22.2 (https://www.ecma-international.org/ecma-262/10.0/index.html#sec-typedarray-objects) of [ECMA-ES10]) ๐. Corresponding implementations [ArrayBuffer] are showing up too ๐ฅ.
Typed arrays can carry serious amounts of data ๐ฆ, so people want to send them over CBOR without having to slowly convert every single number in the array ๐ญ. Encoding a type for each element of an array would also waste space, so this helps with that too ๐.
This document defines a bunch of interrelated CBOR tags that cover these typed arrays, plus extra tags for multi-dimensional and homogeneous arrays ๐ฆ. It's the reference doc for the IANA registration of the tags it defines ๐.
Now, an app that generates CBOR with these tags has a lot of freedom ๐. It can pick variants (like endianness, embedded type signed vs. unsigned, and number of bits per element) ๐ซง. It can also decide whether to use a tag from this spec at all, instead of plain, more basic CBOR ๐. Unlike representation variants of single CBOR numbers, there is no representation that could be identified as "preferred" ๐คทโโ๏ธ. So if a CBOR-based protocol wants deterministic encoding while using these tags, the protocol itself has to define which encoding variants get used in each individual case ๐.
1.1. Terminology ๐
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this doc are to be interpreted as described in BCP 14 [RFC2119] [RFC8174], but only when they appear in all capitals, exactly as shown here ๐. Lowercase versions are just regular words, bestie ๐.
"Byte" means the now-customary synonym for "octet" ๐ซถ. When bit arithmetic gets explained, this doc uses the familiar notation from the programming language C [C] (including C++14's 0bnnn binary literals [CPlusPlus]) ๐ง . The only exception is the operator "**", which means exponentiation ๐ข.
"Array" is used in a general sense here unless it gets more specific ๐ธ. A "classical CBOR array" is an array represented with CBOR major type 4 ๐. A "homogeneous array" is an array where all the elements are the same type ๐. (The term doesn't care whether that type is a representation type or an application data model type ๐ซง.)
"Big endian" and "little endian" mean most significant byte first (MSB first) and least significant byte first (LSB first) representations of integers, respectively โจ.
2. Typed Arrays ๐ฆ
Typed arrays are homogeneous arrays of numbers, and every number is encoded in one single form of binary representation ๐. You concatenate those representations and encode the result as a single CBOR byte string (major type 2) ๐งต. Then it gets wrapped in a single tag that says what type and encoding all the numbers in the byte string have ๐.
2.1. Types of Numbers ๐ฅ
There are three classes of numbers we care about: unsigned integers (uint), signed integers (two's complement, sint), and IEEE 754 binary floating point numbers (which are always signed) ๐. Each of these classes has multiple representation lengths that are actually in use ๐:
+-----------+--------+--------+-----------+
| Length ll | uint | sint | float |
+===========+========+========+===========+
| 0 | uint8 | sint8 | binary16 |
+-----------+--------+--------+-----------+
| 1 | uint16 | sint16 | binary32 |
+-----------+--------+--------+-----------+
| 2 | uint32 | sint32 | binary64 |
+-----------+--------+--------+-----------+
| 3 | uint64 | sint64 | binary128 |
+-----------+--------+--------+-----------+
Table 1: Length Values
Here, sintN means a signed integer of exactly N bits (like sint16), and uintN means an unsigned integer of exactly N bits (like uint32) ๐งฎ. The name binaryN means the number form of the same name defined in IEEE 754 [IEEE754] ๐ค.
Here's the big reason for all this: one goal of these tags is to directly ship the ArrayBuffers underlying the Typed Arrays without re-encoding them ๐. Those buffers might be big-endian (network byte order) or little-endian, so we need tags for both variants ๐.
All in all, that's 24 variants ๐. In the tag, we have to express the choice between integer and float, the signedness (for integers), the endianness, and one of the four length values ๐.
To keep implementation simple, a range of tags is allocated so you can pull all of this info straight from the bits of the tag: tag values from 64 to 87 ๐งโโ๏ธ.
The value is split into bit fields: 0b010, f, s, e, and ll, as detailed in Table 2 ๐ฆ.
+-------+-------------------------------------------------------+
| Field | Use |
+=======+=======================================================+
| 0b010 | the constant bits 0, 1, 0 |
+-------+-------------------------------------------------------+
| f | 0 for integer, 1 for float |
+-------+-------------------------------------------------------+
| s | 0 for float or unsigned integer, 1 for signed integer |
+-------+-------------------------------------------------------+
| e | 0 for big endian, 1 for little endian |
+-------+-------------------------------------------------------+
| ll | A number for the length (Table 1). |
+-------+-------------------------------------------------------+
Table 2: Bit Fields in the Low 8 Bits of the Tag
To get the number of bytes in each array element, you compute "2**(f + ll)" (or "1 << (f + ll)" in a typical programming language) ๐ง . (Notice that 0f and ll are the two least significant bits, respectively, of each 4-bit nibble in the byte ๐.)
In the CBOR representation, the total number of elements isn't written out explicitly ๐คทโโ๏ธ. It's implied from the length of the byte string and the length of each representation ๐งฉ. You can compute it from the length, in bytes, of the byte string holding the array's representation by inverting the previous formula: "bytelength >> (f + ll)" ๐.
For the uint8/sint8 values, the endianness is redundant ๐. So only the tag for the big-endian variant is used and assigned as such ๐. The tag that would signify the little-endian variant of sint8 MUST NOT be used, and its tag number is marked as reserved ๐ซ.
As a special case, the tag that would signify the little-endian variant of uint8 is instead assigned to signify that the numbers in the array use clamped conversion from integers ๐. This is described in more detail in Section 7.1.11 (http://www.ecma-international.org/ecma-262/6.0/#sec-touint8clamp) of the ES10 JavaScript specification ("ToUint8Clamp") [ECMA-ES10] ๐. The assumption is that a program-internal representation of this array, after decoding, would be marked this way for further processing, which gives you "roundtripping" of JavaScript-typed arrays through CBOR ๐.
IEEE 754 binary floating numbers are always signed ๐. So for the float variants (where "f" == 1), there's no need to tell signed and unsigned apart, and the "s" bit is always zero ๐ธ. The tag numbers where "s" would be one (tag values 88 to 95) stay free for other specifications to use ๐.
3. Additional Array Tags ๐งโโ๏ธ
This spec defines three additional array tags ๐ . The Multi-dimensional Array tags can be combined with classical CBOR arrays as well as with Typed Arrays, so you can build multi-dimensional arrays with constant numbers of elements in the sub-arrays ๐. The Homogeneous Array tag lets an app flag a classical CBOR array as a homogeneous array, even when a Typed Array doesn't apply ๐ซถ.
3.1. Multi-dimensional Array ๐
okay so a multi-dimensional array is basically a tagged array that holds two one-dimensional arrays ๐ The first one lists the dimensions (outer ones first, inner ones last) and the second one holds the actual contents. And if that second array is itself tagged as a Typed Array, the element type of the whole thing is the same as that Typed Array's type ๐ซถ
This spec defines two tags: one for elements in row-major order and one for column-major order [RowColMajor] ๐ฆ
3.1.1. Row-Major Order
Tag: 40 โจ
Data Item: Array (major type 4) of two arrays: one array (major type 4) of dimensions, which are unsigned integers distinct from zero; and one array (any one of a CBOR array of major type 4, a Typed Array, or a Homogeneous Array) of elements.
the data in the second array is a run of consecutive values where the last dimension is the contiguous one (row-major order) ๐
Figure 1 shows a 2D array declared in C, then how it looks in CBOR using both the multi-dimensional array tag and the typed array tag. this is the glow-up ๐คฉ
uint16_t a[2][3] = {
{2, 4, 8}, /* row 0 */
{4, 16, 256},
};
<Tag 40> # multi-dimensional array tag
82 # array(2)
82 # array(2)
02 # unsigned(2) 1st Dimension
03 # unsigned(3) 2nd Dimension
<Tag 65> # uint16 array
4c # byte string(12)
0002 # unsigned(2)
0004 # unsigned(4)
0008 # unsigned(8)
0004 # unsigned(4)
0010 # unsigned(16)
0100 # unsigned(256)
Figure 1: Multi-dimensional Array in C and CBOR
Figure 2 is the same 2D array but with the multi-dimensional array tag paired with a basic CBOR array instead. with the small numbers picked for this example, it just happens to be shorter ๐
<Tag 40> # multi-dimensional array tag
82 # array(2)
82 # array(2)
02 # unsigned(2) 1st Dimension
03 # unsigned(3) 2nd Dimension
86 # array(6)
02 # unsigned(2)
04 # unsigned(4)
08 # unsigned(8)
04 # unsigned(4)
10 # unsigned(16)
19 0100 # unsigned(256)
Figure 2: Multi-dimensional Array Using Basic CBOR Array
3.1.2. Column-Major Order
the multi-dimensional arrays in the previous sub-subsection (3.1.1) are in "row major" order, and that's the preferred order for this spec ๐ the column-major version is the analogous one, and it lives under tag 1040 ๐ Figure 3 shows it.
Tag: 1040 ๐ง
Data Item: The same as tag 40, except the data in the second array consists of consecutive values where the first dimension is considered contiguous (column-major order).
<Tag 1040> # multi-dimensional array tag, column-major order
82 # array(2)
82 # array(2)
02 # unsigned(2) 1st Dimension
03 # unsigned(3) 2nd Dimension
86 # array(6)
02 # unsigned(2)
04 # unsigned(4)
04 # unsigned(4)
10 # unsigned(16)
08 # unsigned(8)
19 0100 # unsigned(256)
Figure 3: Multi-dimensional Array Using Basic CBOR Array, Column-Major Order
3.2. Homogeneous Array ๐ฆ
Tag: 41 ๐
Data Item: Array (major type 4)
this tag marks a classic CBOR array (a one-dimensional array) as a homogeneous array, meaning every element is the same application model data type ๐ The element type gets decided by the type of the first element.
this is useful for application data models that give homogeneous arrays special meaning. also, in some cases, strongly typed languages can build native homogeneous arrays of a specific type instead of plain ordered lists while decoding โจ which CBOR data items count as the same application type is up to the application.
Figure 4 is an example of a homogeneous array of booleans in C++ [CPlusPlus] and CBOR ๐ธ
bool boolArray[2] = { true, false };
<Tag 41> # Homogeneous Array Tag
82 #array(2)
F5 # true
F4 # false
Figure 4: Homogeneous Array in C++ and CBOR
Figure 5 levels it up with a more complex structure ๐ง
typedef struct {
bool active;
int value;
} foo;
foo myArray[2] = { {true, 3}, {true, -4} };
<Tag 41>
82 # array(2)
82 # array(2)
F5 # true
03 # 3
82 # array(2)
F5 # true
23 # -4
Figure 5: Homogeneous Array in C++ and CBOR
4. Discussion ๐ฌ
support for both little- and big-endian representation might feel a bit off for CBOR, since CBOR is otherwise fully big endian ๐ but it fits the whole point of typed arrays, which is not having to convert every single element โจ
this spec uses a pretty big chunk of the single-byte tag space ๐ that's justified by how widely typed arrays get used in data interchange ๐
a column-major variant of the multi-dimensional array might seem unnecessary to some and handy to others ๐ฆ it's cheap to define the extra tag, so it's there when you actually need it. putting it in a different number space makes the preference for row-major obvious ๐
applying the Homogeneous Array tag to a Typed Array would usually be redundant, so this spec doesn't provide it ๐
5. CDDL Typenames ๐
For use with CDDL [RFC8610], the typenames in Figure 6 are recommended ๐ซถ
ta-uint8 = #6.64(bstr)
ta-uint16be = #6.65(bstr)
ta-uint32be = #6.66(bstr)
ta-uint64be = #6.67(bstr)
ta-uint8-clamped = #6.68(bstr)
ta-uint16le = #6.69(bstr)
ta-uint32le = #6.70(bstr)
ta-uint64le = #6.71(bstr)
ta-sint8 = #6.72(bstr)
ta-sint16be = #6.73(bstr)
ta-sint32be = #6.74(bstr)
ta-sint64be = #6.75(bstr)
; reserved: #6.76(bstr)
ta-sint16le = #6.77(bstr)
ta-sint32le = #6.78(bstr)
ta-sint64le = #6.79(bstr)
ta-float16be = #6.80(bstr)
ta-float32be = #6.81(bstr)
ta-float64be = #6.82(bstr)
ta-float128be = #6.83(bstr)
ta-float16le = #6.84(bstr)
ta-float32le = #6.85(bstr)
ta-float64le = #6.86(bstr)
ta-float128le = #6.87(bstr)
homogeneous<array> = #6.41(array)
multi-dim<dim, array> = #6.40([dim, array])
multi-dim-column-major<dim, array> = #6.1040([dim, array])
Figure 6: Recommended Typenames for CDDL
6. IANA Considerations ๐
Okay so IANA has allocated the tags in Table 3, and this document is the specification reference for them ๐ (the reserved value is saved for a future revision of typed array tags, so no touching ๐ โโ๏ธ).
The allocations came from the "specification required" space (24..255), with one exception: 1040 came from the "first come first served" space (256..) โจ
+------+----------------------+----------------------------+
| Tag | Data Item | Semantics |
+======+======================+============================+
| 40 | array of two arrays* | Multi-dimensional Array, |
| | | row-major order |
+------+----------------------+----------------------------+
| 41 | array | Homogeneous Array |
+------+----------------------+----------------------------+
| 64 | byte string | uint8 Typed Array |
+------+----------------------+----------------------------+
| 65 | byte string | uint16, big endian, Typed |
| | | Array |
+------+----------------------+----------------------------+
| 66 | byte string | uint32, big endian, Typed |
| | | Array |
+------+----------------------+----------------------------+
| 67 | byte string | uint64, big endian, Typed |
| | | Array |
+------+----------------------+----------------------------+
| 68 | byte string | uint8 Typed Array, clamped |
| | | arithmetic |
+------+----------------------+----------------------------+
| 69 | byte string | uint16, little endian, |
| | | Typed Array |
+------+----------------------+----------------------------+
| 70 | byte string | uint32, little endian, |
| | | Typed Array |
+------+----------------------+----------------------------+
| 71 | byte string | uint64, little endian, |
| | | Typed Array |
+------+----------------------+----------------------------+
| 72 | byte string | sint8 Typed Array |
+------+----------------------+----------------------------+
| 73 | byte string | sint16, big endian, Typed |
| | | Array |
+------+----------------------+----------------------------+
| 74 | byte string | sint32, big endian, Typed |
| | | Array |
+------+----------------------+----------------------------+
| 75 | byte string | sint64, big endian, Typed |
| | | Array |
+------+----------------------+----------------------------+
| 76 | byte string | (reserved) |
+------+----------------------+----------------------------+
| 77 | byte string | sint16, little endian, |
| | | Typed Array |
+------+----------------------+----------------------------+
| 78 | byte string | sint32, little endian, |
| | | Typed Array |
+------+----------------------+----------------------------+
| 79 | byte string | sint64, little endian, |
| | | Typed Array |
+------+----------------------+----------------------------+
| 80 | byte string | IEEE 754 binary16, big |
| | | endian, Typed Array |
+------+----------------------+----------------------------+
| 81 | byte string | IEEE 754 binary32, big |
| | | endian, Typed Array |
+------+----------------------+----------------------------+
| 82 | byte string | IEEE 754 binary64, big |
| | | endian, Typed Array |
+------+----------------------+----------------------------+
| 83 | byte string | IEEE 754 binary128, big |
| | | endian, Typed Array |
+------+----------------------+----------------------------+
| 84 | byte string | IEEE 754 binary16, little |
| | | endian, Typed Array |
+------+----------------------+----------------------------+
| 85 | byte string | IEEE 754 binary32, little |
| | | endian, Typed Array |
+------+----------------------+----------------------------+
| 86 | byte string | IEEE 754 binary64, little |
| | | endian, Typed Array |
+------+----------------------+----------------------------+
| 87 | byte string | IEEE 754 binary128, little |
| | | endian, Typed Array |
+------+----------------------+----------------------------+
| 1040 | array of two arrays* | Multi-dimensional Array, |
| | | column-major order |
+------+----------------------+----------------------------+
Table 3: Values for Tags
*40 or 1040 data item: The second element of the outer array in the
data item is a native CBOR array (major type 4) or Typed Array (one
of tag 64..87)
7. Security Considerations ๐
Big safety talk, bestie ๐ซถ The security considerations of [RFC7049] apply, and you need to give special attention to the second paragraph of Section 8 of [RFC7049] ๐
The tag for homogeneous arrays makes a promise about its tagged data item, and a maliciously constructed CBOR input can then choose to ignore that promise ๐ญ So the decoder has to make sure it is not driven into an undefined state by array elements that do not fulfill the promise, and that it still continues to fulfill its API contract in this case too. No skipping this part, periodt ๐
As with all formats used for data interchange, an attacker may have control over the shape of the data delivered as input to the application. That means the application needs to validate that shape before it builds further processing on top of it ๐จ Typed arrays add one extra twist: an attacker might swap a Uint8ClampedArray in where the application expects a Uint8Array, or the other way around. That can lead to very different (and unexpected) processing semantics for the in-memory data structures that get built ๐ So applications that could be affected will need to be careful about making this distinction in their input validation. Main character energy is validating everything ๐
8. References ๐
8.1. Normative References
- [C] International Organization for Standardization, "Information technology - Programming languages - C", ISO/IEC 9899:2018, Fourth Edition, June 2018.
- [CPlusPlus] International Organization for Standardization, "Programming languages - C++", ISO/IEC 14882:2017, Fifth Edition, December 2017.
- [ECMA-ES10] ECMA International, "ECMAScript 2019 Language Specification", Standard ECMA-262 10th Edition, June 2019,
https://www.ecma-international.org/ecma-262/10.0/index.html. - [IEEE754] IEEE, "IEEE Standard for Floating-Point Arithmetic", IEEE 754-2019, DOI 10.1109/IEEESTD.2019.8766229,
https://ieeexplore.ieee.org/document/8766229. - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997,
https://www.rfc-editor.org/info/rfc2119. - [RFC7049] Bormann, C. and P. Hoffman, "Concise Binary Object Representation (CBOR)", RFC 7049, DOI 10.17487/RFC7049, October 2013,
https://www.rfc-editor.org/info/rfc7049. - [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017,
https://www.rfc-editor.org/info/rfc8174. - [RFC8610] Birkholz, H., Vigano, C., and C. Bormann, "Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610, June 2019,
https://www.rfc-editor.org/info/rfc8610.
8.2. Informative References
- [ArrayBuffer] Mozilla Developer Network, "JavaScript typed arrays", June 2010,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays. - [RowColMajor] Wikipedia, "Row- and column-major order", September 2019,
https://en.wikipedia.org/w/index.php?title=Row-_and_column-major_order&oldid=917905325. - [TypedArray] Vukicevic, V. and K. Russell, "Typed Array Specification", February 2011,
https://web.archive.org/web/20110207024413/http://www.khronos.org/registry/typedarray/specs/latest/.
Acknowledgements ๐
Jim Schaad gave helpful comments and reminded everyone that column-major order is still in use ๐ธ Jeffrey Yaskin helped improve the definition of homogeneous arrays ๐ IANA helped correct an error in a previous draft version ๐ง Francesca Palombini acted as Shepherd, and Alexey Melnikov was the responsible Area Director ๐ Elwyn Davies, as Gen-ART reviewer, and IESG members Martin Vigoureux, Adam Roach, Roman Danyliw, and Benjamin Kaduk helped find further improvements to the text. Thanks also to the other reviewers, you're all iconic โจ
Contributors ๐ฆ
The initial draft version of this specification was written by Johnathan Roatch <roatch@gmail.com>. Many thanks for getting this ball rolling ๐
Glenn Engel suggested the tags for multi-dimensional arrays and homogeneous arrays ๐
Author's Address ๐
Carsten Bormann (editor)
Universitรคt Bremen TZI
Postfach 330440
D-28359 Bremen
Germany
Phone: +49-421-218-63921
Email: cabo@tzi.org
๐ฆ where this page comes from
- ietf: rfc8746 2020-02
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms