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:
Severiano Jaramillo 2024-04-12 16:25:18 -07:00
parent 7dab5227dc
commit 53bc55ec9f
3 changed files with 73 additions and 28 deletions

View file

@ -20,11 +20,16 @@ kotlin {
sourceSets { sourceSets {
commonMain.dependencies { commonMain.dependencies {
implementation(projects.shared.crypto)
implementation(libs.cryptography.bigint)
implementation(libs.ktor.client.cio) implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.core) implementation(libs.ktor.client.core)
implementation(libs.ktor.client.websockets) implementation(libs.ktor.client.websockets)
}
implementation(libs.cryptography.bigint) commonTest.dependencies {
implementation(libs.kotlin.test)
} }
} }
} }

View file

@ -2,6 +2,8 @@ package net.agorise.shared.stargate.mnemonics
import dev.whyoleg.cryptography.bigint.BigInt import dev.whyoleg.cryptography.bigint.BigInt
import dev.whyoleg.cryptography.bigint.toBigInt 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. * Provides functionality to create and validate mnemonics.
@ -115,33 +117,31 @@ class Mnemonics {
// //
// return calculatedChecksumWord == checksumWord // return calculatedChecksumWord == checksumWord
// } // }
//
// /** /**
// * Calculates a checksum (using CRC algorithm) on first 24 words. * 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
// @OptIn(ExperimentalUnsignedTypes::class) * - Calculates the CRC-32 checksum on the concatenated bytes
// private fun calculateChecksumIndex(words: Array<String>, prefixLen: Int): Result<UInt> { * - Returns the mod of checksum by SEED_LENGTH, to get the checksum word
// val trimmedRunes = mutableListOf<Char>() */
// internal fun calculateChecksumIndex(words: List<String>, prefixLen: Int): Result<UInt> {
// if (words.size != SEED_LENGTH) { if (words.size != SEED_LENGTH) {
// return Result.failure(Exception("Words not equal to seed length")) return Result.failure(Exception("Words not equal to seed length"))
// } }
//
// for (word in words) { val trimmedWords = mutableListOf<Char>()
// val trimmedWord = if (word.length > prefixLen) {
// word.substring(0, prefixLen) words.forEach { word ->
// } else { trimmedWords.addAll(word.take(prefixLen).toList())
// word }
// }
// trimmedRunes.addAll(trimmedWord.toCharArray().toList()) // TODO Use DI to get an instance of CRC32
// } val crc32 = Crc32()
//
// val checksum = CRC32().apply { val checksum = crc32.crc32(trimmedWords.joinToString("").toByteArray())
// update(trimmedRunes.toCharArray().concatToString().toByteArray(Charsets.UTF_8))
// }.value return Result.success(checksum % SEED_LENGTH.toUInt())
// }
// return Result.success(checksum % SEED_LENGTH.toUInt())
// }
companion object { companion object {
// Each language should have exactly this number of words // Each language should have exactly this number of words

View file

@ -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)
}
}