All Downloads are FREE. Search and download functionalities are using the official Maven repository.

co.topl.crypto.generation.mnemonic.Language.scala Maven / Gradle / Ivy

The newest version!
package co.topl.crypto.generation.mnemonic

import cats.implicits._
import co.topl.crypto.hash.sha256
import io.estatico.newtype.macros.newtype
import io.estatico.newtype.ops._

import java.nio.charset.StandardCharsets
import scala.language.implicitConversions
import scala.util.Try

/**
 * Represents a set of 2048 words that can be used to create a mnemonic.
 *
 * @param filePath the location of the words list
 * @param hash     the SHA-256 hash of the words for verification
 */
sealed abstract class Language(val filePath: String, val hash: String) {
  private val wordlistDirectory: String = "bip-0039"
}

/**
 * Enumeration of languages that mnemonics can be generated in
 */
object Language {

  case object ChineseSimplified
      extends Language("chinese_simplified.txt", "bfd683b91db88609fabad8968c7efe4bf69606bf5a49ac4a4ba5e355955670cb")

  case object ChineseTraditional
      extends Language("chinese_traditional.txt", "85b285c4e0e3eb1e52038e2cf4b4f8bba69fd814e1a09e063ce3609a1f67ad62")

  case object English
      extends Language("english.txt", "ad90bf3beb7b0eb7e5acd74727dc0da96e0a280a258354e7293fb7e211ac03db")

  case object French extends Language("french.txt", "9cbdaadbd3ce9cbaee1b360fce45e935b21e3e2c56d9fcd56b3398ced2371866")

  case object Italian
      extends Language("italian.txt", "80d2e90d7436603fd6e57cd9af6f839391e64beac1a3e015804f094fcc5ab24c")

  case object Japanese
      extends Language("japanese.txt", "d9d1fde478cbeb45c06b93632a487eefa24f6533970f866ae81f136fbf810160")

  case object Korean extends Language("korean.txt", "f04f70b26cfef84474ff56582e798bcbc1a5572877d14c88ec66551272688c73")

  case object Spanish
      extends Language("spanish.txt", "a556a26c6a5bb36db0fb7d8bf579cb7465fcaeec03957c0dda61b569962d9da5")

  case object Czech extends Language("czech.txt", "f9016943461800f7870363b4c301c814dbcb8f4de801e6c87d859eba840469d5")

  case object Portuguese
      extends Language("portuguese.txt", "eed387d44cf8f32f60754527e265230d8019e8a2277937c71ef812e7a46c93fd")

  /**
   * A list of valid words in a language for generating a mnemonic phrase.
   *
   * @param value the valid words for creating phrases
   */
  @newtype
  class LanguageWordList(val value: IndexedSeq[String])

  object LanguageWordList {

    /**
     * A failure to import a word list into a collection.
     */
    sealed trait ValidationFailure

    case class FileReadFailure(exception: Throwable) extends ValidationFailure

    case class InvalidChecksum() extends ValidationFailure

    /**
     * Verifies the wordlist for the given language by calculating the SHA-256 hash
     *
     * @return a validated word list or a `WordListFailure` of type `InvalidChecksum`
     */
    private def validateChecksum(
      words:        IndexedSeq[String],
      expectedHash: String
    ): Either[ValidationFailure, IndexedSeq[String]] =
      Either.cond(
        sha256
          .hash(words.mkString.getBytes(StandardCharsets.UTF_8))
          .value
          .map(byte => "%02x" format byte)
          .mkString == expectedHash,
        words,
        InvalidChecksum()
      )

    /**
     * Read the word list for the specified language and validate it with its specified hash value.
     * @param language The language to read a word list for
     * @return The work list or an error
     */
    def validated(language: Language): Either[ValidationFailure, LanguageWordList] =
      Try(
        scala.io.Source.fromResource(s"${language.wordlistDirectory}/${language.filePath}").getLines().toIndexedSeq
      ).toEither
        .leftMap(FileReadFailure)
        .flatMap(words =>
          validateChecksum(words, language.hash)
            .map(_.coerce)
        )
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy