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:
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:
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:
To interpret each character directly, use a type cast:
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.
Sizing
In order to obtain the length of a sequence of bytes, use the
predefined function Bytes.length like so:
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.
Bitwise operations
The bitwise operations on sequences of bytes are as follows:
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.
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.
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: