Add calculateChecksumIndex() method to Mnemonics class.
- The calculateChecksumIndex() method uses the newly added method to calculate the CRC-32 to obtain the index of the word to be used for the seed checksum. - Added a few unit tests to validate the correct functionality of the calculateChecksumIndex() method.
This commit is contained in:
parent
7dab5227dc
commit
53bc55ec9f
3 changed files with 73 additions and 28 deletions
|
@ -20,11 +20,16 @@ kotlin {
|
|||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(projects.shared.crypto)
|
||||
|
||||
implementation(libs.cryptography.bigint)
|
||||
implementation(libs.ktor.client.cio)
|
||||
implementation(libs.ktor.client.core)
|
||||
implementation(libs.ktor.client.websockets)
|
||||
}
|
||||
|
||||
implementation(libs.cryptography.bigint)
|
||||
commonTest.dependencies {
|
||||
implementation(libs.kotlin.test)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package net.agorise.shared.stargate.mnemonics
|
|||
|
||||
import dev.whyoleg.cryptography.bigint.BigInt
|
||||
import dev.whyoleg.cryptography.bigint.toBigInt
|
||||
import io.ktor.utils.io.core.toByteArray
|
||||
import net.agorise.shared.crypto.crc.Crc32
|
||||
|
||||
/**
|
||||
* Provides functionality to create and validate mnemonics.
|
||||
|
@ -115,33 +117,31 @@ class Mnemonics {
|
|||
//
|
||||
// return calculatedChecksumWord == checksumWord
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Calculates a checksum (using CRC algorithm) on first 24 words.
|
||||
// */
|
||||
// @OptIn(ExperimentalUnsignedTypes::class)
|
||||
// private fun calculateChecksumIndex(words: Array<String>, prefixLen: Int): Result<UInt> {
|
||||
// val trimmedRunes = mutableListOf<Char>()
|
||||
//
|
||||
// if (words.size != SEED_LENGTH) {
|
||||
// return Result.failure(Exception("Words not equal to seed length"))
|
||||
// }
|
||||
//
|
||||
// for (word in words) {
|
||||
// val trimmedWord = if (word.length > prefixLen) {
|
||||
// word.substring(0, prefixLen)
|
||||
// } else {
|
||||
// word
|
||||
// }
|
||||
// trimmedRunes.addAll(trimmedWord.toCharArray().toList())
|
||||
// }
|
||||
//
|
||||
// val checksum = CRC32().apply {
|
||||
// update(trimmedRunes.toCharArray().concatToString().toByteArray(Charsets.UTF_8))
|
||||
// }.value
|
||||
//
|
||||
// return Result.success(checksum % SEED_LENGTH.toUInt())
|
||||
// }
|
||||
|
||||
/**
|
||||
* Calculates a checksum using CRC-32 algorithm on the seed (SEED_LENGTH words) as follows:
|
||||
* - Takes prefixLen chars (not bytes) from each word and concatenates them
|
||||
* - Calculates the CRC-32 checksum on the concatenated bytes
|
||||
* - Returns the mod of checksum by SEED_LENGTH, to get the checksum word
|
||||
*/
|
||||
internal fun calculateChecksumIndex(words: List<String>, prefixLen: Int): Result<UInt> {
|
||||
if (words.size != SEED_LENGTH) {
|
||||
return Result.failure(Exception("Words not equal to seed length"))
|
||||
}
|
||||
|
||||
val trimmedWords = mutableListOf<Char>()
|
||||
|
||||
words.forEach { word ->
|
||||
trimmedWords.addAll(word.take(prefixLen).toList())
|
||||
}
|
||||
|
||||
// TODO Use DI to get an instance of CRC32
|
||||
val crc32 = Crc32()
|
||||
|
||||
val checksum = crc32.crc32(trimmedWords.joinToString("").toByteArray())
|
||||
|
||||
return Result.success(checksum % SEED_LENGTH.toUInt())
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Each language should have exactly this number of words
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package net.agorise.shared.stargate.mnemonics
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class MnemonicsTest {
|
||||
private val mnemonics = Mnemonics()
|
||||
|
||||
@Test
|
||||
fun `given an invalid seed - when calculateChecksumIndex is called - then result is failure`() {
|
||||
val invalidSeed = "invalid seed".split(" ")
|
||||
|
||||
val result = mnemonics.calculateChecksumIndex(invalidSeed, 3)
|
||||
|
||||
assertTrue(result.isFailure)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a valid english seed - when calculateChecksumIndex is called - then result is correct`() {
|
||||
val expectedChecksumIndex = 22u
|
||||
val seed = "sequence atlas unveil summon pebbles tuesday beer rudely snake rockets different fuselage woven tagged bested dented vegan hover rapid fawns obvious muppet randomly seasons randomly".split(" ").dropLast(1)
|
||||
|
||||
val result = mnemonics.calculateChecksumIndex(seed, 3)
|
||||
val actualChecksumIndex = result.getOrThrow()
|
||||
|
||||
assertEquals(expectedChecksumIndex, actualChecksumIndex)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a valid spanish seed - when calculateChecksumIndex is called - then result is correct`() {
|
||||
val expectedChecksumIndex = 7u
|
||||
val seed = "perfil lujo faja puma favor pedir detalle doble carbón neón paella cuarto ánimo cuento conga correr dental moneda león donar entero logro realidad acceso doble".split(" ").dropLast(1)
|
||||
|
||||
val result = mnemonics.calculateChecksumIndex(seed, 4)
|
||||
val actualChecksumIndex = result.getOrThrow()
|
||||
|
||||
assertEquals(expectedChecksumIndex, actualChecksumIndex)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue