You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dependabot[bot] 82c164c6be
Bump actions/checkout from 3.3.0 to 3.5.0
3 days ago
.github Bump actions/checkout from 3.3.0 to 3.5.0 3 days ago
.run [#41] Add dependency update gradle task 10 months ago
bip39-lib [#144] Kotlin 1.8.10 2 months ago
build-conventions-bip39 [#144] Kotlin 1.8.10 2 months ago
docs [#95] Fix publishing all variants 8 months ago
gradle [#150] Simplify Detekt configuration 2 months ago
tools [#150] Simplify Detekt configuration 2 months ago
.git-blame-ignore-revs [#31] Configure multiplatform build scripts 11 months ago
.gitignore Add .DS_Store to gitignore 11 months ago Prepare development for 1.0.4 release 8 months ago
LICENSE Initial commit 3 years ago [#95] Fix publishing all variants 8 months ago
build.gradle.kts [#150] Simplify Detekt configuration 2 months ago
buildscript-gradle.lockfile [#144] Kotlin 1.8.10 2 months ago
gradle.lockfile [#129] Ktlint 0.48.2 2 months ago [#144] Kotlin 1.8.10 2 months ago
gradlew [#120] Gradle 7.6 3 months ago
gradlew.bat [#120] Gradle 7.6 3 months ago
settings-gradle.lockfile [#31] Configure multiplatform build scripts 11 months ago
settings.gradle.kts [#65] Support included builds 10 months ago


license maven


A concise implementation of BIP-0039 in Kotlin for Android.

Only about 30kB in total size. For comparison, the entire library is about 3X the size of this README file (because there are no dependencies)!


  • There are not many bip-39 implementations for android
  • Most that do exist are not Kotlin
    • or they are not idiomatic (because they are direct Java ports to Kotlin)
    • or they have restrictive licenses
  • Most implementations fail to validate the checksum, which can easily lead to loss of funds!
    • validating the checksum prevents: leading/trailing white space, valid words in the wrong order, mistyping a valid word (like chief instead of chef) and other similar issues that could invalidate a backup or lose funds.
  • No other implementation uses CharArrays, from the ground up, for added security and lower chances of accidentally logging sensitive info.

Consequently, this library strives to use both idiomatic Kotlin and CharArrays whenever possible. It also aims to be concise and thoroughly tested. As a pure kotlin library, it probably also works outside of Android but that is not an explicit goal (Update: confirmed to also work on a Ktor server).

Plus, it uses a permissive MIT license and no dependencies beyond Kotlin's stdlib!

Getting Started


Add dependencies (see Maven badge above for latest version number):

dependencies {
    implementation "${latestVersion}"

repository {


This library prefers CharArrays over Strings for added security.
Note: If strings or lists are desired, it is very easy (but not recommended) to convert to/from a CharArray via String(charArray) or String(charArray).split(' ').

  • Create new 24-word mnemonic phrase

val mnemonicCode: MnemonicCode = MnemonicCode(WordCount.COUNT_24)

// assert: mnemonicCode.wordCount == 24, mnemonicCode.languageCode == "en"
  • Generate seed
val seed: ByteArray = mnemonicCode.toSeed()
  • Generate seed from existing mnemonic
val preExistingPhraseString = "scheme spot photo card baby mountain device kick cradle pact join borrow"
val preExistingPhraseChars = validPhraseString.toCharArray()

// from CharArray
seed = MnemonicCode(preExistingPhraseChars).toSeed()

// from String
seed = MnemonicCode(preExistingPhraseString).toSeed()
  • Generate seed with passphrase
// normal way
val passphrase = "bitcoin".toCharArray()

// more private way (erase at the end)
charArrayOf('z', 'c', 'a', 's', 'h').let { passphrase ->
    passphrase.fill('0') // erased!
  • Generate raw entropy for a corresponding word count
val entropy: ByteArray = WordCount.COUNT_18.toEntropy()

// this can be used to directly generate a mnemonic:
val mnemonicCode = MnemonicCode(entropy)

// note: that gives the same result as calling:
  • Validate pre-existing or user-provided mnemonic
    (NOTE: mnemonics generated by the library "from scratch" are valid, by definition)
// throws a typed exception when invalid:
//     ChecksumException - when checksum fails, usually meaning words are swapped
//     WordCountException(count) - invalid number of words
//     InvalidWordException(word) - contains a word not found on the list
  • Iterate over words
// mnemonicCodes are iterable
for (word in mnemonicCode) {

mnemonicCode.forEach { word ->
  • Clean up!
mnemonicCode.clear() // code words are deleted and no longer available for attacker

Advanced Usage

These generated codes are compatible with kotlin's scoped resource usage

  • Leverage use to automatically clean-up after use
MnemonicCode(WordCount.COUNT_24).use {
    // Do something with the words (wordCount == 24)
// memory has been cleared at this point (wordCount == 0)
  • Generate original entropy that was used to create the mnemonic (or throw exception if the mnemonic is invalid).
    • Note: Calling this function only succeeds when the entropy is valid so it also can be used, indirectly, for validation. In fact, currently, it is called as part of the MnemonicCode::validate() function.
val entropy: ByteArray = MnemonicCode(preExistingPhraseString).toEntropy()
  • Mnemonics generated by the library do not need to be validated while creating the corresponding seed. That step can be skipped for a little added speed and security (because validation generates strings on the heap--which might get improved in a future release).
seed = MnemonicCode(WordCount.COUNT_24).toSeed(validate = false)
  • Other languages are not yet supported but the API for them is in place. It accepts any ISO 639-1 language code. For now, using it with anything other than "en" will result in an UnsupportedOperationException.
// results in exception, for now
val mnemonicCode = MnemonicCode(WordCount.COUNT_24, languageCode = Locale.GERMAN.language)

// english is the only language that doesn't crash
val mnemonicCode = MnemonicCode(WordCount.COUNT_24, languageCode = Locale.ENGLISH.language)

Known issues

  • When publishing the library, a Gradle warning will be printed. This is a known issue in Kotlin Multiplatform and can be safely ignored.


  • zcash/ebfull - Zcash core dev and BIP-0039 co-author who inspired creation of this library
  • bitcoinj - Java implementation from which much of this code was adapted
  • Trezor - for their OG test data set that has excellent edge cases
  • Cole Barnes - whose PBKDF2SHA512 Java implementation is floating around everywhere online
  • Ken Sedgwick - who adapted Cole Barnes' work to use SHA-512