BCS
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
@Serializabledata 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.
-
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:
Codeimplementation("xyz.mcxross.bcs:bcs-android:0.1.3") implementation("xyz.mcxross.bcs:bcs-js:0.1.3") -
Apply the serialization plugin in your build file:
Codeplugins { 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
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
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, andCharthrowNotSupported.- Sequence and container sizes are length-prefixed with ULEB128.
- Maximum sequence length and container depth are enforced internally.