The QCAT Standard: Understanding Byte Encodings for Length Representation

mvryo
4 min readOct 8, 2024

--

In programming, it’s common to deal with lengths or sizes of data. Depending on the size of that data, we represent its length using bytes. But how exactly does this encoding work? Let’s break it down step by step.

What is a Byte?

A byte is a unit of data that consists of 8 bits. Each bit is a binary value, meaning it can either be a 0 or a 1. For example, if we have a sequence of 8 bits, it might look like this:

00000000

That’s a byte with all zeroes.

How We Encode Lengths Using Bytes

When encoding a length in bytes, we need to consider how large that length is. The larger the number, the more bytes we need to represent it. Let’s look at an example to make this clearer.

Example 1: Length = 255

Let’s say we have the value 255, and we want to encode this length in bytes. Since 255 can fit in 1 byte (8 bits), it’s simple. The binary representation of 255 is:

11111111

This is the maximum value you can store in a single byte.

Now, if we represent this in hexadecimal (which is base-16), 11111111 becomes FF. So, in hexadecimal, 255 is represented as:

FF

When we apply this to our code, we see that for a length of 255, we use a 2-byte encoding because of the condition that values greater than or equal to 128 require extra bytes:

byteArrayOf(0x81.toByte(), 0xFF.toByte())

Here:

  • 0x81.toByte() is a special marker that tells the system we are using 2 bytes.
  • 0xFF.toByte() is the actual length, encoded in a single byte.

Example 2: Length = 256

What if the length is 256? Since 256 is greater than what we can store in 1 byte, we need to use 2 bytes (or 16 bits) to represent this length. The 16-bit binary representation of 256 looks like this:

00000001  - 2nd byte
00000000 - 1st byte

If we convert this to hexadecimal, we get:

01 00

In the code, when we encounter a length of 256, we enter the else condition that handles lengths larger than 255, which requires 3 bytes of encoding:

byteArrayOf(0x82.toByte(), 0x01.toByte(), 0x00.toByte())

Here:

  • 0x82.toByte() is a marker that indicates we’re using 3 bytes for the length.
  • 0x01.toByte() and 0x00.toByte() represent the high and low bytes of the length 256, respectively.

Why Do We Need Different Byte Encodings?

The reason we use different encodings is efficiency. For small lengths (less than 128), we can fit the value into 1 byte, which saves space. As the length grows, we need more bytes to accurately represent the number, but by using markers like 0x81 and 0x82, we help the system understand how many bytes are being used for the length.

Recap of the Implementation

Here is our implementation of the function that converts a length into its corresponding hex string representation, depending on whether it requires 1, 2, or 3 bytes of encoding:

private fun encodeLengthToHexString(length: Int): String {
val bytes = when {
length < 128 -> byteArrayOf(length.toByte()) // 1-byte length encoding
length <= 255 -> byteArrayOf(0x81.toByte(), length.toByte()) // 2-byte length encoding
else -> byteArrayOf(0x82.toByte(), (length shr 8).toByte(), length.toByte()) // 3-byte length encoding
}

return bytes.joinToString("") { String.format("%02X", it) }
}

This function takes an integer length as input and:

  • Uses 1 byte if the length is less than 128.
  • Uses 2 bytes if the length is between 128 and 255.
  • Uses 3 bytes for lengths greater than 255.

It then returns the encoded length as a hexadecimal string.

Conclusion

In summary, encoding lengths into bytes depends on the size of the value. Small values can fit in 1 byte, but larger values require 2 or 3 bytes. By using this encoding system, we ensure efficient storage and handling of data lengths, while the system knows exactly how many bytes to expect for any given value.

By understanding how binary and hexadecimal representations work, you can better manage length encodings in your programs and ensure your data is handled correctly.

If you’d like to learn more or get involved in the QCAT ecosystem, feel free to check out my guides on QCAT specification below or check out AF Payments Inc.’s GitHub for the latest updates and contribution guidelines.

DISCLAIMER

The information provided in this article is for informational purposes only and does not constitute professional advice. While efforts have been made to ensure accuracy, AF Payments Inc. reserves the right to update or modify the QCAT standard and related materials at any time. Use of the QCAT standard is subject to the terms of its license agreement, and any implementation must adhere to AFPI’s guidelines and licensing requirements. For the latest details and official documentation, please refer to AF Payments Inc.’s authorized channels.

--

--

mvryo
mvryo

Written by mvryo

I share stories and insights from my 8+ years in IT, aiming to inspire and empower others with practical knowledge and personal experiences in tech.

No responses yet