Byte Array Methods
Sia provides methods for writing and reading raw Uint8Array data. Byte array methods come in two flavors: with a length prefix (self-describing) and without a length prefix (fixed-size). All methods are available as both class methods and standalone functions:
// Class API
import { Sia } from "@timeleap/sia";
// Functional API (tree-shakeable)
import { Buffer, addByteArray8, readByteArray8 } from "@timeleap/sia";
With Length Prefix
These methods prepend the byte array's length before the data, so the reader knows how many bytes to consume. The number suffix indicates the bit width of the length prefix.
addByteArray8(bytes) / readByteArray8(asReference?)
Writes or reads a byte array with an 8-bit (1 byte) length prefix. Maximum array length: 255 bytes.
addByteArray8(bytes: Uint8Array): Sia
readByteArray8(asReference?: boolean): Uint8Array
| Parameter | Type | Default | Description |
|---|---|---|---|
bytes | Uint8Array | — | The byte array to write |
asReference | boolean | false | If true, returns a subarray (zero-copy) |
const sia = new Sia();
const data = new Uint8Array([1, 2, 3, 4, 5]);
sia.addByteArray8(data);
sia.seek(0);
const result = sia.readByteArray8();
console.log(result); // Uint8Array [1, 2, 3, 4, 5]
addByteArray16(bytes) / readByteArray16(asReference?)
Writes or reads a byte array with a 16-bit (2 byte) length prefix. Maximum array length: 65,535 bytes.
addByteArray16(bytes: Uint8Array): Sia
readByteArray16(asReference?: boolean): Uint8Array
| Parameter | Type | Default | Description |
|---|---|---|---|
bytes | Uint8Array | — | The byte array to write |
asReference | boolean | false | If true, returns a subarray (zero-copy) |
const sia = new Sia();
const data = new Uint8Array([10, 20, 30, 40, 50]);
sia.addByteArray16(data);
sia.seek(0);
const result = sia.readByteArray16();
console.log(result); // Uint8Array [10, 20, 30, 40, 50]
addByteArray32(bytes) / readByteArray32(asReference?)
Writes or reads a byte array with a 32-bit (4 byte) length prefix. Maximum array length: ~4 GB.
addByteArray32(bytes: Uint8Array): Sia
readByteArray32(asReference?: boolean): Uint8Array
| Parameter | Type | Default | Description |
|---|---|---|---|
bytes | Uint8Array | — | The byte array to write |
asReference | boolean | false | If true, returns a subarray (zero-copy) |
const sia = new Sia();
const data = new Uint8Array(100).map((_, i) => i);
sia.addByteArray32(data);
sia.seek(0);
const result = sia.readByteArray32();
console.log(result.length); // 100
addByteArray64(bytes) / readByteArray64(asReference?)
Writes or reads a byte array with a 64-bit (8 byte) length prefix.
addByteArray64(bytes: Uint8Array): Sia
readByteArray64(asReference?: boolean): Uint8Array
| Parameter | Type | Default | Description |
|---|---|---|---|
bytes | Uint8Array | — | The byte array to write |
asReference | boolean | false | If true, returns a subarray (zero-copy) |
const sia = new Sia();
const data = new Uint8Array(50).map((_, i) => (i * 2) % 256);
sia.addByteArray64(data);
sia.seek(0);
const result = sia.readByteArray64();
console.log(result.length); // 50
Without Length Prefix
addByteArrayN(bytes) / readByteArrayN(length, asReference?)
Writes or reads a byte array without any length prefix. You must know the exact length at read time.
addByteArrayN(bytes: Uint8Array): Sia
readByteArrayN(length: number, asReference?: boolean): Uint8Array
| Parameter | Type | Default | Description |
|---|---|---|---|
bytes | Uint8Array | — | The byte array to write |
length | number | — | Exact number of bytes to read |
asReference | boolean | false | If true, returns a subarray (zero-copy) |
Throws: "Not enough data to read byte array" if there are insufficient bytes to read.
This is useful when the byte length is implied by the protocol (e.g., a 32-byte public key always has a known size).
const sia = new Sia();
// Write a 32-byte public key (no length prefix needed)
const publicKey = new Uint8Array(32).fill(0xab);
sia.addByteArrayN(publicKey);
sia.seek(0);
// Read exactly 32 bytes
const key = sia.readByteArrayN(32);
console.log(key.length); // 32
The asReference Parameter
All readByteArray* methods accept an optional asReference parameter that controls memory allocation behavior.
asReference is false (default), readByteArray* returns a copy of the data using slice(). This is safe to store, modify, and pass around independently.When asReference is true, it returns a subarray that shares memory with the Sia buffer. This avoids a memory allocation but means changes to the original buffer will affect the returned array.const sia = new Sia();
sia.addByteArray8(new Uint8Array([1, 2, 3]));
sia.seek(0);
// Returns an independent copy
const copy = sia.readByteArray8(false);
copy[0] = 99; // Does NOT affect the Sia buffer
const sia = new Sia();
sia.addByteArray8(new Uint8Array([1, 2, 3]));
sia.seek(0);
// Returns a view into the same memory
const ref = sia.readByteArray8(true);
// ref shares memory with sia.content — use immediately
When to use asReference = true:
- Decoding performance is critical and you will consume the data immediately
- You are reading data only to pass it to another function (e.g.,
TextDecoder.decode()) - You are building a streaming pipeline where copies are wasteful
When to use the default (false):
- You need to store the result for later use
- The Sia buffer may be reused or modified
- You are using the default shared buffer
Length Prefix Sizes
| Method | Prefix Size | Max Array Length |
|---|---|---|
addByteArray8 | 1 byte | 255 bytes |
addByteArray16 | 2 bytes | 65,535 bytes |
addByteArray32 | 4 bytes | ~4.29 GB |
addByteArray64 | 8 bytes | ~2^53 bytes |
addByteArrayN | 0 bytes | Caller-specified |
Complete Example
Serializing a message with a public key, signature, and variable-length payload:
import { Sia } from "@timeleap/sia";
// Serialize a signed message
const sia = new Sia();
const publicKey = new Uint8Array(32).fill(0x01); // 32-byte Ed25519 key
const signature = new Uint8Array(64).fill(0x02); // 64-byte signature
const payload = new TextEncoder().encode("Transfer 100 tokens to Alice");
sia
.addByteArrayN(publicKey) // Fixed 32 bytes — no prefix needed
.addByteArrayN(signature) // Fixed 64 bytes — no prefix needed
.addByteArray16(payload); // Variable length — needs a prefix
const bytes = sia.toUint8Array();
console.log(bytes.length);
// 32 + 64 + 2 (prefix) + 28 (payload) = 126 bytes
// Deserialize
const reader = new Sia(bytes);
const readKey = reader.readByteArrayN(32);
const readSig = reader.readByteArrayN(64);
const readPayload = reader.readByteArray16();
console.log(new TextDecoder().decode(readPayload));
// "Transfer 100 tokens to Alice"