BCS

AndroidiOSNodeJSJVMmacOSLinuxWindows

Use the BCS library to perform deterministic binary serialization that works across the Kotlin Multiplatform targets. It implements the Binary Canonical Serialization format as a kotlinx.serialization encoder/decoder and is used by projects such as Sui and Aptos.

BCS is not self-describing. The receiver must know the exact type and structure to decode a byte array.

Key Features

  • Target Android, iOS, JVM, Node.js, macOS, Linux, and Windows from one codebase.
  • Annotate regular @Serializable data classes and get BCS encoding for free.
  • Obtain canonical byte output suitable for hashes, signatures, and consensus.
  • Get a small, allocation-light implementation backed by custom ULEB128 and length-prefixed buffers.

Installation

Add the dependency for your setup. You also need the Kotlinx Serialization compiler plugin.

  1. Add the artifact (version 0.1.3):

    Code
    // commonMain (recommended for KMP) implementation("xyz.mcxross.bcs:bcs:0.1.3")

    Platform-specific artifacts are also published:

    Code
    implementation("xyz.mcxross.bcs:bcs-android:0.1.3") implementation("xyz.mcxross.bcs:bcs-js:0.1.3")
  2. Apply the serialization plugin in your build file:

    Code
    plugins { kotlin("plugin.serialization") version "2.0.0" // match your Kotlin version }

Quick Start

Create an instance with Bcs {} (the builder form used throughout the library tests and samples) and call encodeToByteArray / decodeFromByteArray.

Basic types

Code
import xyz.mcxross.bcs.Bcs val bcs = Bcs {} val boolBytes = bcs.encodeToByteArray(true) // [1] val intBytes = bcs.encodeToByteArray(42) // ULEB128 encoded val textBytes = bcs.encodeToByteArray("hello") // length (ULEB128) + UTF-8 val decoded = bcs.decodeFromByteArray<String>(textBytes)

User-defined types

Code
import kotlinx.serialization.Serializable import xyz.mcxross.bcs.Bcs @Serializable data class Payload( val amount: Long, val active: Boolean, val memo: String ) val bcs = Bcs {} val data = Payload(1_000_000L, true, "transfer") val bytes: ByteArray = bcs.encodeToByteArray(data) val back: Payload = bcs.decodeFromByteArray(bytes)

Collections, enums, and nested data classes are supported as long as all leaf types are handled by the encoder (Long, Int, Short, Byte, Boolean, String, Unit, and collections of the above).

Notes from the implementation

  • Double, Float, and Char throw NotSupported.
  • Sequence and container sizes are length-prefixed with ULEB128.
  • Maximum sequence length and container depth are enforced internally.

Reference & Resources