Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add mnemonic validation #94

Merged
merged 1 commit into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,33 @@ final class Mnemonic {

private const val PBKDF2C = 2048
private const val PBKDF2DKLen = 64
class InvalidMnemonicCode(code: String) : RuntimeException(code)

fun isValidMnemonicCode(code: Array<String>): Boolean {
return code.all { it in MnemonicCodeEnglish.wordList }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to support for the other languages that we currently provides.

Copy link
Contributor Author

@goncalo-frade-iohk goncalo-frade-iohk Sep 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is on commonMain so all platforms are supported no?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @hamada147 means spoken languages, not coding languages. Is that correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well although the code is there for other languages we actually don't support or use it.

Copy link
Contributor

@hamada147 hamada147 Sep 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, @cristianIOHK. I meant not only handle MnemonicCodeEnglish but also the others

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah although I agree with you both. At some point we decided to just use English for now, since it's our case, we left the other languages list in the code, but you check that we just use the English. ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we use English only right now. You can ignore my comment as I thought we are supporting the others as well.

}

fun createRandomMnemonics(): Array<String> {
val entropyBytes = SecureRandom.generateSeed(SEED_ENTROPY_BITS_24_WORDS / 8)
return MnemonicCode(MnemonicCodeEnglish.wordList.toTypedArray()).toMnemonic(entropyBytes)
}

fun createSeed(mnemonics: String, passphrase: String = "AtalaPrism"): ByteArray {
@Throws(InvalidMnemonicCode::class)
fun createSeed(mnemonics: Array<String>, passphrase: String = "AtalaPrism"): ByteArray {
if (!isValidMnemonicCode(mnemonics)) {
throw InvalidMnemonicCode(mnemonics.joinToString(separator = " "))
}
val mnemonicString = mnemonics.joinToString(separator = " ")
return PBKDF2SHA512.derive(
mnemonics,
mnemonicString,
passphrase,
PBKDF2C,
PBKDF2DKLen
)
}

fun createRandomSeed(passphrase: String = "AtalaPrism"): ByteArray {
val mnemonics = this.createRandomMnemonics().joinToString(separator = " ")
val mnemonics = this.createRandomMnemonics()
return this.createSeed(mnemonics, passphrase)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@ import io.iohk.atala.prism.apollo.hashing.internal.toHexString
import kotlin.test.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse

class MnemonicTests {

@Test
fun testValidateMnemonics() {
val invalidMnemonics = arrayOf("abc", "ddd", "inv")
assertFalse(Mnemonic.isValidMnemonicCode(invalidMnemonics))
}

@Test
fun testCreateRandomMnemonics() {
val mnemonics = Mnemonic.createRandomMnemonics().joinToString(separator = " ")
val mnemonics = Mnemonic.createRandomMnemonics()
val seed = Mnemonic.createSeed(mnemonics)
assertEquals(seed.size, 64)
}
Expand All @@ -21,24 +30,34 @@ class MnemonicTests {

@Test
fun testCreateSeed() {
val mnemonics = "random seed mnemonic words"
val mnemonics = arrayOf("adjust", "animal", "anger", "around")
val seed = Mnemonic.createSeed(mnemonics)

assertEquals(seed.size, 64)

val privateKey = seed.slice(IntRange(0, 31))
assertContains(privateKey.toByteArray().toHexString(), "feac83cecc84531575eb67250a03d8ac112d4d6678674968bf3f6576ad028ae3")
assertContains(privateKey.toByteArray().toHexString(), "a078d8a0f3beca52ef17a1d0279eb6e9c410cd3837d3db38d31e43df6da95ac6")
}

@Test
fun testCreateSeedInvalidMnemonics() {
val mnemonics = arrayOf("abc", "ddd", "adsada", "testing")

assertFailsWith<Mnemonic.Companion.InvalidMnemonicCode> {
Mnemonic.createSeed(mnemonics)
}
}

@Test
fun testCreateSeedWithPW() {
val mnemonics = "random seed mnemonic words"
val mnemonics = arrayOf("adjust", "animal", "anger", "around")
val password = "123456"
val seed = Mnemonic.createSeed(mnemonics, password)

assertEquals(seed.size, 64)

val privateKey = seed.slice(IntRange(0, 31))
assertContains(privateKey.toByteArray().toHexString(), "b3a8af66eca002e8b4ca868c5b55a8c865f15e0cfea483d6a164a6fbecf83625")

assertContains(privateKey.toByteArray().toHexString(), "815b70655ca4c9675f5fc15fe8f82315f07521d034eec45bf4d5912bd3a61218")
}
}
Loading