Electric-Coin-Company / kotlin-bip39

A concise implementation of BIP-0039 in Kotlin for Android. In order, it prioritizes being secure, concise and idiomatic.
MIT License
35 stars 8 forks source link
aar android bip39 bip39-mnemonic-codes ecc kotlin library mnemonic zcash

kotlin-bip39

license maven

Introduction

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)!

Motivation

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

Gradle

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

dependencies {
    implementation "cash.z.ecc.android:kotlin-bip39:${latestVersion}"
}

repository {
    mavenCentral()
}

Usage

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(' ').

val mnemonicCode: MnemonicCode = MnemonicCode(WordCount.COUNT_24)

// assert: mnemonicCode.wordCount == 24, mnemonicCode.languageCode == "en"

* Generate seed
```kotlin
val seed: ByteArray = mnemonicCode.toSeed()

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

// from String seed = MnemonicCode(preExistingPhraseString).toSeed()

* Generate seed with passphrase
```kotlin
// normal way
val passphrase = "bitcoin".toCharArray()
mnemonicCode.toSeed(passphrase)

// more private way (erase at the end)
charArrayOf('z', 'c', 'a', 's', 'h').let { passphrase ->
    mnemonicCode.toSeed(passphrase)
    passphrase.fill('0') // erased!
}

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

// note: that gives the same result as calling: MnemonicCode(WordCount.COUNT_18)

* Validate pre-existing or user-provided mnemonic  
  (NOTE: mnemonics generated by the library "from scratch" are valid, by definition)
```kotlin
// 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
mnemonicCode.validate()

mnemonicCode.forEach { word -> println(word) }

* Clean up!
```kotlin
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

// 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](https://youtrack.jetbrains.com/issue/KT-46466) in Kotlin Multiplatform and can be safely ignored.

## Credits
* [zcash/ebfull](https://github.com/ebfull) - Zcash core dev and BIP-0039 co-author who inspired creation of this library
* [bitcoinj](https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/crypto/MnemonicCode.java) - Java implementation from which much of this code was adapted
* [Trezor](https://github.com/trezor/python-mnemonic/blob/master/vectors.json) - for their OG [test data set](https://github.com/trezor/python-mnemonic/blob/master/vectors.json) that has excellent edge cases
* [Cole Barnes](http://cryptofreek.org/2012/11/29/pbkdf2-pure-java-implementation/) - whose PBKDF2SHA512 Java implementation is floating around _everywhere_ online
* [Ken Sedgwick](https://github.com/ksedgwic) - who adapted Cole Barnes' work to use SHA-512