Add verifyChecksum method to Mnemonics class.
- The verifyChecksum() method uses the calculateChecksumIndex() method internally to obtain the checksum index, which is then used to confirm that the checksum word is correct. - Added tests for all verifyChecksum() scenarios. - Created MnemonicsDataProvider to more easily provide the data used in MnemonicsTest.
This commit is contained in:
parent
53bc55ec9f
commit
c690d839da
4 changed files with 86 additions and 25 deletions
|
@ -1,11 +1,16 @@
|
|||
package net.agorise.shared.crypto.crc
|
||||
|
||||
/**
|
||||
* Provides functionality to calculate CRC-32 checksums.
|
||||
*
|
||||
* 0xEDB88320u is the reversed representation of the IEEE CRC-32 polynomial: 0x04C11DB7
|
||||
*/
|
||||
class Crc32(private val polynomial: UInt = 0xEDB88320u) {
|
||||
class Crc32(polynomial: UInt = 0xEDB88320u) {
|
||||
internal val lookupTable: List<UInt> = populateLookupTable(polynomial)
|
||||
|
||||
/**
|
||||
* Calculates the CRC-32 checksum on the given byte array.
|
||||
*/
|
||||
fun crc32(bytes: ByteArray): UInt {
|
||||
var crc = INITIAL_CRC32
|
||||
for (byte in bytes) {
|
||||
|
@ -15,6 +20,9 @@ class Crc32(private val polynomial: UInt = 0xEDB88320u) {
|
|||
return crc.inv()
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the lookup table with the given polynomial to calculate CRC-32 checksums faster.
|
||||
*/
|
||||
private fun populateLookupTable(polynomial: UInt): List<UInt> {
|
||||
return (0 until 256).map { index ->
|
||||
(0 until 8).fold(index.toUInt()) { crc, _ ->
|
||||
|
|
|
@ -99,24 +99,23 @@ class Mnemonics {
|
|||
)
|
||||
|
||||
/**
|
||||
* Verifies that the
|
||||
* Obtains that the checksum index and verifies it corresponds to the checksum word.
|
||||
*/
|
||||
// private fun verifyChecksum(words: Array<String>, prefixLen: Int): Boolean {
|
||||
// val seedLength = SEED_LENGTH
|
||||
//
|
||||
// if (words.size != seedLength + 1) {
|
||||
// return false // Checksum word is not present, we cannot verify
|
||||
// }
|
||||
//
|
||||
// val (checksumIndex, err) = calculateChecksumIndex(words.sliceArray(0 until words.size - 1), prefixLen)
|
||||
// if (err != null) {
|
||||
// return false
|
||||
// }
|
||||
// val calculatedChecksumWord = words[checksumIndex]
|
||||
// val checksumWord = words[seedLength]
|
||||
//
|
||||
// return calculatedChecksumWord == checksumWord
|
||||
// }
|
||||
internal fun verifyChecksum(words: List<String>, prefixLen: Int): Boolean {
|
||||
if (words.size != SEED_LENGTH + 1) {
|
||||
return false // Checksum word is not present, we cannot verify
|
||||
}
|
||||
|
||||
val result = calculateChecksumIndex(words.dropLast(1), prefixLen)
|
||||
|
||||
// Obtain checksum index, or return false if checksum index is not present
|
||||
val checksumIndex = result.getOrNull()?.toInt() ?: return false
|
||||
|
||||
val calculatedChecksumWord = words[checksumIndex]
|
||||
val checksumWord = words[SEED_LENGTH]
|
||||
|
||||
return calculatedChecksumWord == checksumWord
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a checksum using CRC-32 algorithm on the seed (SEED_LENGTH words) as follows:
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package net.agorise.shared.stargate.mnemonics
|
||||
|
||||
object MnemonicsDataProvider {
|
||||
val invalidSizeSeed = "invalid size seed".split(" ")
|
||||
val invalidChecksumSeed =
|
||||
("sequence atlas unveil summon pebbles tuesday beer rudely snake rockets different " +
|
||||
"fuselage woven tagged bested dented vegan hover rapid fawns obvious muppet " +
|
||||
"randomly seasons summon").split(" ")
|
||||
val validEnglishSeed =
|
||||
("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(" ")
|
||||
val validSpanishSeed =
|
||||
("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(" ")
|
||||
}
|
|
@ -2,16 +2,17 @@ package net.agorise.shared.stargate.mnemonics
|
|||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
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(" ")
|
||||
fun `given an invalid size seed - when calculateChecksumIndex is called - then result is failure`() {
|
||||
val invalidSizeSeed = MnemonicsDataProvider.invalidSizeSeed
|
||||
|
||||
val result = mnemonics.calculateChecksumIndex(invalidSeed, 3)
|
||||
val result = mnemonics.calculateChecksumIndex(invalidSizeSeed, 3)
|
||||
|
||||
assertTrue(result.isFailure)
|
||||
}
|
||||
|
@ -19,9 +20,9 @@ class MnemonicsTest {
|
|||
@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 validEnglishSeed = MnemonicsDataProvider.validEnglishSeed.dropLast(1)
|
||||
|
||||
val result = mnemonics.calculateChecksumIndex(seed, 3)
|
||||
val result = mnemonics.calculateChecksumIndex(validEnglishSeed, 3)
|
||||
val actualChecksumIndex = result.getOrThrow()
|
||||
|
||||
assertEquals(expectedChecksumIndex, actualChecksumIndex)
|
||||
|
@ -30,11 +31,47 @@ class MnemonicsTest {
|
|||
@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 validSpanishSeed = MnemonicsDataProvider.validSpanishSeed.dropLast(1)
|
||||
|
||||
val result = mnemonics.calculateChecksumIndex(seed, 4)
|
||||
val result = mnemonics.calculateChecksumIndex(validSpanishSeed, 4)
|
||||
val actualChecksumIndex = result.getOrThrow()
|
||||
|
||||
assertEquals(expectedChecksumIndex, actualChecksumIndex)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given an invalid size seed - when verifyChecksum is called - then result is false`() {
|
||||
val invalidSizeSeed = MnemonicsDataProvider.invalidSizeSeed
|
||||
|
||||
val result = mnemonics.verifyChecksum(invalidSizeSeed, 3)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given an invalid checksum seed - when verifyChecksum is called - then result is false`() {
|
||||
val invalidChecksumSeed = MnemonicsDataProvider.invalidChecksumSeed
|
||||
|
||||
val result = mnemonics.verifyChecksum(invalidChecksumSeed, 3)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a valid english seed - when verifyChecksum is called - then result is true`() {
|
||||
val validEnglishSeed = MnemonicsDataProvider.validEnglishSeed
|
||||
|
||||
val result = mnemonics.verifyChecksum(validEnglishSeed, 3)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a valid spanish seed - when verifyChecksum is called - then result is true`() {
|
||||
val validSpanishSeed = MnemonicsDataProvider.validSpanishSeed
|
||||
|
||||
val result = mnemonics.verifyChecksum(validSpanishSeed, 4)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue