kodium
1.0.0indexedHigh-speed, pure-language cryptography implementing TweetNaCl primitives (Box, SecretBox, Ed25519), Base58Check, PBKDF2, secure key import/export, encoding utilities and opinionated APIs—no native dependencies.
High-speed, pure-language cryptography implementing TweetNaCl primitives (Box, SecretBox, Ed25519), Base58Check, PBKDF2, secure key import/export, encoding utilities and opinionated APIs—no native dependencies.
Secure. Portable. Pure Kotlin.
Kodium is a comprehensive, pure Kotlin Multiplatform (KMP) cryptography library. It acts as a faithful port of the renowned TweetNaCl C library, providing high-speed, high-security cryptographic primitives, advanced Double Ratchet session management, and Post-Quantum Cryptography (PQC) protocols without any native dependencies.
Write once, encrypt everywhere. Even in a post-quantum world.
kotlincrypto library for improved performance and stability.Kodium.pqc namespace with support for Hybrid ML-KEM-768 + X25519 encryption.Add Kodium to your common module's dependencies.
Gradle (Kotlin DSL)
implementation("eu.livotov.labs:kodium:1.1.0")
Gradle (Groovy)
implementation 'eu.livotov.labs:kodium:1.1.0'
Maven
<dependency>
<groupId>eu.livotov.labs</groupId>
<artifactId>kodium</artifactId>
<version>1.1.0</version>
</dependency>
Kodium provides a complete implementation of the Double Ratchet algorithm for secure E2EE messaging.
// Alice initializes her session as the initiator
val aliceSession = DoubleRatchetSession.initializeAsInitiator(sharedSecret, responderRatchetKey)
// Encrypt a message to a Base58 string
val encrypted = aliceSession.encryptToEncodedString("Hello Bob!".encodeToByteArray()).getOrThrow()
// Bob decrypts it back
val bobSession = DoubleRatchetSession.initializeAsResponder(sharedSecret, responderRatchetKeyPair)
val decrypted = bobSession.decryptFromEncodedString(encrypted).getOrThrow()
Upgrade your E2EE sessions to be resistant to quantum computer attacks using the PQDoubleRatchetSession.
// Alice initializes her PQ session using the secrets from PQXDH
val aliceSession = PQDoubleRatchetSession.initializeAsInitiator(
sharedSecret = aliceSharedSecret.masterSecret,
responderPqcPublicKey = fetchedBobBundle.pqcKey,
ourPqcPrivateKey = aliceHybridKeys
)
val encrypted = aliceSession.encryptToEncodedString("Post-Quantum Hello!".encodeToByteArray()).getOrThrow()
// Bob initializes his session using his keys and Alice's provided payload
val bobSession = PQDoubleRatchetSession.initializeAsResponder(
sharedSecret = bobSharedSecret,
ourPqcPrivateKey = bobHybridKeys,
initiatorPqcPublicKey = fetchedAlicePayload.pqcPublicKey!!
)
val decrypted = bobSession.decryptFromEncodedString(encrypted).getOrThrow()
Protect your data against future quantum computer attacks using the hybrid Kodium.pqc suite.
// 1. Generate Hybrid Keys (X25519 + ML-KEM-768)
val myKeys = Kodium.pqc.generateKeyPair()
val theirPublicKey = ... // Received from peer
// 2. Encrypt
val encrypted = Kodium.pqc.encryptToEncodedString(
mySecretKey = myKeys,
theirPublicKey = theirPublicKey,
data = "Secret message".encodeToByteArray()
).getOrThrow()
// 3. Decrypt
val decrypted = Kodium.pqc.decryptFromEncodedString(
mySecretKey = myKeys,
theirPublicKey = theirPublicKey,
data = encrypted
).getOrThrow()
Securely exchange messages between Alice and Bob without session management.
// 1. Generate keys
val alice = Kodium.generateKeyPair()
val bob = Kodium.generateKeyPair()
// 2. Alice encrypts a message for Bob
val message = "The eagle flies at midnight.".encodeToByteArray()
val encryptedResult = Kodium.encryptToEncodedString(
mySecretKey = alice,
theirPublicKey = bob.getPublicKey(),
data = message
)
// 3. Bob decrypts the message
encryptedResult.onSuccess { cipherText ->
Kodium.decryptFromEncodedString(
mySecretKey = bob,
theirPublicKey = alice.getPublicKey(),
data = cipherText
).onSuccess { decryptedBytes ->
println()
}
}
Protect data with a shared password/secret.
val password = "CorrectHorseBatteryStaple"
val secretData = "Launch codes: 12345".encodeToByteArray()
// Encrypt
val encryptedResult = Kodium.encryptSymmetricToEncodedString(password, secretData)
// Decrypt
encryptedResult.onSuccess { cipherText ->
val decryptedResult = Kodium.decryptSymmetricFromEncodedString(password, cipherText)
println("Restored: ${decryptedResult.getOrThrow().decodeToString()}")
}
Prove authenticity and integrity using detached Ed25519 digital signatures.
val myPrivateKey = Kodium.generateKeyPair()
val message = "This message is authentic".encodeToByteArray()
// Sign
val signatureB58 = Kodium.signDetachedToEncodedString(myPrivateKey, message).getOrThrow()
// Verify using the signer's Public Key
val isValid = Kodium.verifyDetachedFromEncodedString(
theirPublicKey = myPrivateKey.getPublicKey(),
data = message,
signatureB58 = signatureB58
)
Easily store keys using Base58Check encoding.
val keyPair = Kodium.generateKeyPair()
// Export Public Key (Safe to share, contains both encryption and signing keys)
val pubKeyString = keyPair.getPublicKey().exportToEncodedString()
// Export Private Key (Encrypted with a password)
val privKeyString = keyPair.exportToEncryptedString("StrongPassword")
// Import later
val restoredKeyPair = KodiumPrivateKey.importFromEncryptedString(
data = privKeyString.getOrThrow(),
password = "StrongPassword"
)
A hybrid key can be derived from 32 bytes of entropy, which can be written down as 24 BIP-39 words. For example, Keylane prints such a "paper key" so that a user who loses every device can type the words into a fresh install and get back exactly the same key pair.
// Create: 32 random bytes -> key pair + 24 words to write down
val entropy = Kodium.generateHighEntropyKey()
val paperKey = Kodium.pqc.generateKeyPair(entropy) // deterministic
val words = Bip39.encode(entropy) // 24 words
// Restore on a new device: words -> the very same key pair
val restored = Bip39.decode(typedWords) ?: error("A word is misspelled or out of order")
val sameKey = Kodium.pqc.generateKeyPair(restored)
Bip39.isWord and Bip39.complete validate and autocomplete each word while the user types. The entropy is as sensitive as the private key, so zero it once you are done. See Seeded Keys & Mnemonics.
The complete documentation for Kodium is available online and within the repository.
👉 Online Documentation (Manual & API Reference)
The docs/ directory is structured for GitBook and contains:
For advanced usage and detailed technical explanations, refer to our deep-dive standalone guides.
Learn how to build a fully secure, asynchronous peer-to-peer chat application using the classical Double Ratchet protocol. This guide covers the complete lifecycle:
👉 Read the full Double Ratchet & X3DH Guide
Future-proof your application against "Harvest Now, Decrypt Later" attacks by upgrading to Kodium's Hybrid PQC suite. This guide covers:
👉 Read the full PQC Reference Guide
We welcome contributions! If you're interested in building Kodium from source, running tests, or updating the documentation, please refer to our Developer Guide.
Kodium is licensed under the Apache 2.0 License.
The Post-Quantum ML-KEM math implementation in this project is based on the excellent KyberKotlin project by Ron Lauren Hombre.
The BIP-39 English wordlist embedded in io.kodium.mnemonic comes from BIP 39 by Marek Palatinus, Pavol Rusnak, Aaron Voisine and Sean Bowe. It is used under the MIT License; the full notice is in Bip39EnglishWordlist.kt.
Copyright 2026 Livotov Labs Ltd.
Disclaimer: While this library implements standard cryptographic primitives based on TweetNaCl, it has not been audited by a security expert. Users should always review security requirements for their specific use case and use at their own risk.
PQDoubleRatchetSession. It works with both 1.0.0 and 1.1.0 peers. The ML-KEM variant of a key (MlKemVariant.FIPS_203 or MlKemVariant.LEGACY) is recognised from the key material and followed automatically. Nothing changes on the wire or in any storage format.Kodium.pqc.generateKeyPair() and MLKEM.keyPair() now produce FIPS 203 keys, which Kodium 1.0.0 peers cannot encrypt to. Existing keys are not affected. During a rolling upgrade, use Kodium.pqc.generateKeyPair(MlKemVariant.LEGACY) for keys that 1.0.0 peers must reach. KodiumPqcPublicKey.mlKemVariant helps you find legacy keys to rotate later. See ML-KEM Variants.Kodium.pqc.generateKeyPair(seed) derives a hybrid key pair deterministically from 32 bytes. The same seed gives a byte-identical key on every platform and in every release. It uses derivation version 1 (HKDF-SHA-256, salt kodium-seeded-hybrid-v1), pinned by golden vectors in seeded-hybrid-vectors.json. Kodium.generateKeyPair(seed) does the same for classical keys (salt kodium-seeded-ed25519-v1).io.kodium.mnemonic.Bip39 encodes 16 to 32 bytes of entropy as 12 to 24 English words with a checksum. It also offers per-word validation and autocomplete, and identical Unicode (NFKD) normalisation on every platform. There is deliberately no mnemonic-to-seed PBKDF2 step.kotlin.io.encoding.Base64...ToEncodedString and ...FromEncodedString methods now use Base64 with a 4-byte checksum for integrity. Method parameters previously named ...B58 have been renamed to ...Base64 for clarity.KodiumPublicKey and KodiumPqcPublicKey to include encryption and signing keys, simplifying key management and ensuring consistent behavior.ByteArray methods for signing and verification (signDetached, verifyDetached) across all namespaces.ByteArray exports and imports (exportToArray(), importFromArray()) across all private keys (KodiumPrivateKey, KodiumPqcPrivateKey) and E2EE sessions (DoubleRatchetSession, PQDoubleRatchetSession) to support apps managing their own secure storage.ByteArray precomputed key support for symmetric encryption and state persistence, allowing developers to bypass PBKDF2 overhead when importing/exporting keys and ratchet sessions.Kodium.generateHighEntropyKey(), Kodium.generateRandomSalt(), and Kodium.deriveKeyFromPassword() to simplify symmetric key lifecycle management.| Platform | Support |
|---|
| Android | ✅ |
| iOS (Arm64, X64, Sim) | ✅ |
| JVM (Java 17+) | ✅ |
| JavaScript (Browser/Node) | ✅ |
| Wasm (WebAssembly) | ✅ |
| macOS (Arm64, X64) | ✅ |
| Linux (X64) | ✅ |
| Windows (MinGW X64) | ✅ |
Surfaced from shared tags and platforms — no rankings paid for.