Skip to main content
Version: Next

Bytes

Bytes are used for serializing data, for example to compute signature hashes. Conversely, they can be used to deserialise external data, in which case the expected LIGO type needs to be specified.

Literals

Byte literals are sequences of bytes (eight-bit values, also known as octets), defined using the prefix 0x followed by hexadecimal digits, or none if the denoted literal is zero:

const a : bytes = 0x70FF;
const zero = "" as bytes;
const zero_too = 0x00;

This means that literal bytes are always comprised of an even number of hexadecimal digits, because one hexadecimal digit requires up to four bits in binary, and eight are needed to make up a byte.

From numbers to bytes and back

You can convert some other numerals to bytes by calling the predefined function bytes. To convert ints or nats to bytes, use the predefined functions int and nat. For example, here is how to create bytes from natural numbers and integers:

const b: bytes = bytes(123 as nat); // 7B in hexadecimal
const c: bytes = bytes(123);
const d: bytes = bytes(-123); // Two's complement
const n: nat = nat(0x7B); // n == 123n
const i: int = int(0x7B); // i == 123

Note: See Two's complement.

From strings

You can convert a string literal to bytes in two ways:

  • By interpreting the ASCII code of each character (which spans over two hexadecimal digits) as one byte
  • By interpreting directly each character as one hexadecimal digit

To interpret the ASCII code, use this syntax:

const from_ascii: bytes = bytes`foo`; // Not a function call

To interpret each character directly, use a type cast:

// raw == from_ascii
const raw: bytes = ("666f6f" as bytes);
note

Both cases apply only to string literals, not variables or other expressions of type string. In other words, the contents of the strings must be available in-place at compile time. (This reveals that ("666f6f" as bytes) is not really a cast, because casts are non-operations.)

Concatenating

Two or more bytes can be concatenated.

const two: bytes = Bytes.concat(0x70, 0xAA);
const three: bytes = Bytes.concats([0x70, 0xAA, 0xFF]);

Sizing

In order to obtain the length of a sequence of bytes, use the predefined function Bytes.length like so:

const len: nat = Bytes.length(0x0AFF); // len == (2 as nat)

Slicing

You can extract a subset from bytes with the Bytes.sub function. It accepts a nat for the index of the start of the subset and a nat for the number of bytes in the subset. Both numbers are inclusive. The first byte has the index 0.

const large = 0x12345678;
const slice = Bytes.sub(1 as nat, 2 as nat, large); // sub == 0x3456

Bitwise operations

The bitwise operations on sequences of bytes are as follows:

// Bitwise "and"
const and: bytes = 0x0005 & 0x0106; // 0x0004
// Bitwise "or"
const or: bytes = 0x0005 | 0x0106; // 0x0107
// Bitwise "xor"
const xor: bytes = 0x0005 ^ 0x0106; // 0x0103
// Bitwise "shift left"
const shift_left: bytes = 0x06 << (8 as nat); // 0x0600
// Bitwise "shift right"
const shift_right: bytes = 0x0006 >> (1 as nat); // 0x0003

Packing and unpacking

LIGO provides the functions Bytes.pack and Bytes.unpack to serialize and deserialize data into a binary format. These functions correspond to the Michelson instructions PACK and UNPACK. Unpacking may fail, so the return type of Byte.unpack is an option that needs a type annotation.

note

These functions are intended for use by developers who are familiar with data serialization. There are several risks and failure cases, such as unpacking a lambda from an untrusted source or casting the result to the wrong type.

function id_string (p: string) : option<string> {
let packed = Bytes.pack(p);
return Bytes.unpack(packed);
};

Cryptography

One common use of bytes, beyond packing and unpacking, is cryptography. The predefined module Crypto provides the following hashing functions, which are efficient because they are natively supported by the Michelson virtual machine:

const blake2b: bytes => bytes;
const sha256: bytes => bytes;
const sha512: bytes => bytes;
const sha3: bytes => bytes;
const keccak: bytes => bytes;