├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENCE.txt ├── README.md ├── _config.yml ├── bintray.gradle ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── ideaShared └── copyright │ ├── GNU_GPLv3.xml │ └── profiles_settings.xml ├── settings.gradle └── src ├── main └── java │ └── io │ └── github │ └── novacrypto │ └── bip39 │ ├── AlphabeticalCharSequenceComparator.java │ ├── ByteUtils.java │ ├── CharSequenceSplitter.java │ ├── JavaxPBKDF2WithHmacSHA512.java │ ├── MnemonicGenerator.java │ ├── MnemonicValidator.java │ ├── NFKDNormalizer.java │ ├── Normalization.java │ ├── PBKDF2WithHmacSHA512.java │ ├── SeedCalculator.java │ ├── SeedCalculatorByWordListLookUp.java │ ├── SpongyCastlePBKDF2WithHmacSHA512.java │ ├── Validation │ ├── InvalidChecksumException.java │ ├── InvalidWordCountException.java │ ├── UnexpectedWhiteSpaceException.java │ └── WordNotFoundException.java │ ├── WordList.java │ ├── WordListMapNormalization.java │ ├── Words.java │ └── wordlists │ ├── English.java │ ├── French.java │ ├── Japanese.java │ └── Spanish.java └── test ├── java └── io │ └── github │ └── novacrypto │ ├── Hex.java │ ├── MnemonicGenerationTests.java │ ├── MnemonicGenerationWordCountTests.java │ ├── MnemonicValidationTests.java │ ├── Resources.java │ ├── SeedCalculationFromWordListTests.java │ ├── SeedCalculationTests.java │ ├── TestCharSequence.java │ ├── ValidationExceptionMessagesTests.java │ ├── bip39 │ ├── ByteUtilTests.java │ ├── CharSequenceSplitterTests.java │ ├── EnumValueValueOfCodeCoverageTests.java │ ├── NormalizationTests.java │ └── WordListMapNormalizationTests.java │ ├── testjson │ ├── EnglishJson.java │ ├── TestVector.java │ └── TestVectorJson.java │ └── wordlists │ ├── EnglishListContentTests.java │ ├── FrenchListContentTests.java │ ├── JapaneseListContentTests.java │ ├── SpanishListContentTests.java │ └── WordListHashing.java └── resources ├── bip39_english_test_vectors.json ├── bip39_french_test_vectors.json ├── bip39_japanese_test_vectors.json └── bip39_spanish_test_vectors.json /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | out 3 | .gradle/ 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | before_cache: 3 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 4 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 5 | cache: 6 | directories: 7 | - $HOME/.gradle/caches/ 8 | - $HOME/.gradle/wrapper/ 9 | after_success: 10 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Download](https://api.bintray.com/packages/novacrypto/BIP/BIP39/images/download.svg)](https://bintray.com/novacrypto/BIP/BIP39/_latestVersion) [![Build Status](https://travis-ci.org/NovaCrypto/BIP39.svg?branch=master)](https://travis-ci.org/NovaCrypto/BIP39) [![codecov](https://codecov.io/gh/NovaCrypto/BIP39/branch/master/graph/badge.svg)](https://codecov.io/gh/NovaCrypto/BIP39) 2 | 3 | Read all about how I wrote this and understanding BIP39 [here](https://medium.com/@_west_on/coding-a-bip39-microlibrary-in-java-bb90c1109123). 4 | 5 | Apart from generating a seed, only English, French, Spanish and Japanese [currently packaged](https://github.com/NovaCrypto/BIP39/issues/1), but as `WordList` is an interface and you can provide your own. 6 | 7 | # Install 8 | 9 | Use either of these repositories: 10 | 11 | ``` 12 | repositories { 13 | jcenter() 14 | } 15 | ``` 16 | 17 | Or: 18 | 19 | ``` 20 | repositories { 21 | maven { 22 | url 'https://dl.bintray.com/novacrypto/BIP/' 23 | } 24 | } 25 | ``` 26 | 27 | Add dependency: 28 | 29 | ``` 30 | dependencies { 31 | compile 'io.github.novacrypto:BIP39:2019.01.27' 32 | } 33 | 34 | ``` 35 | 36 | # Usage 37 | 38 | ## Generate a mnemonic 39 | 40 | Using a `StringBuilder`: 41 | 42 | ``` 43 | StringBuilder sb = new StringBuilder(); 44 | byte[] entropy = new byte[Words.TWELVE.byteLength()]; 45 | new SecureRandom().nextBytes(entropy); 46 | new MnemonicGenerator(English.INSTANCE) 47 | .createMnemonic(entropy, sb::append); 48 | System.out.println(sb.toString()); 49 | ``` 50 | 51 | If you're paranoid and/or need higher than normal [memory security](https://medium.com/@_west_on/protecting-strings-in-jvm-memory-84c365f8f01c), consider using a [`SecureCharBuffer`](https://github.com/NovaCrypto/SecureString): 52 | 53 | ``` 54 | try (SecureCharBuffer secure = new SecureCharBuffer()) { 55 | byte[] entropy = new byte[Words.TWELVE.byteLength()]; 56 | new SecureRandom().nextBytes(entropy); 57 | new MnemonicGenerator(English.INSTANCE) 58 | .createMnemonic(entropy, secure::append); 59 | Arrays.fill(entropy, (byte) 0); //empty entropy 60 | //do something with your secure mnemonic 61 | } 62 | ``` 63 | 64 | ## Validate a mnemonic 65 | 66 | ``` 67 | try { 68 | MnemonicValidator 69 | .ofWordList(English.INSTANCE) 70 | .validate(mnemonic); 71 | } catch (UnexpectedWhiteSpaceException e) { 72 | ... 73 | } catch (InvalidWordCountException e) { 74 | ... 75 | } catch (InvalidChecksumException e) { 76 | ... 77 | } catch (WordNotFoundException e) { 78 | ... 79 | //e.getSuggestion1() 80 | //e.getSuggestion2() 81 | } 82 | ``` 83 | 84 | Or if you have a list of words from a word list: 85 | 86 | ``` 87 | MnemonicValidator 88 | .ofWordList(English.INSTANCE) 89 | .validate(mnemonicWordsInAList); 90 | ``` 91 | 92 | ## Generate a seed 93 | 94 | As does not use a word list, can be used now for any language. 95 | 96 | ``` 97 | byte[] seed = new SeedCalculator().calculateSeed(mnemonic, passphrase); 98 | ``` 99 | 100 | Or if you have a list of words from a word list: 101 | 102 | ``` 103 | byte[] seed = new SeedCalculator() 104 | .withWordsFromWordList(English.INSTANCE) 105 | .calculateSeed(mnemonicWordsInAList, passphrase); 106 | ``` 107 | 108 | Note: it will work for words off of the word list, but it allows use of secure CharSequences if they match the wordlist, normalized or not (as they are never `toString`ed) 109 | 110 | Those examples both use SpongyCastle, if you don't need or want that dependency, you can use `javax.crypto` like so: 111 | 112 | ``` 113 | byte[] seed = new SeedCalculator(JavaxPBKDF2WithHmacSHA512.INSTANCE).calculateSeed(mnemonic, passphrase); 114 | ``` 115 | 116 | That will not work on Android API < 26 https://developer.android.com/reference/javax/crypto/SecretKeyFactory.html and see Issue #17. 117 | 118 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-hacker -------------------------------------------------------------------------------- /bintray.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | // Generate a dependency version update report for release 23 | // ./gradlew dependencyUpdates -Drevision=release 24 | // https://github.com/ben-manes/gradle-versions-plugin 25 | apply plugin: 'com.github.ben-manes.versions' 26 | apply plugin: 'com.jfrog.bintray' 27 | apply plugin: 'maven-publish' 28 | apply plugin: 'jacoco' 29 | 30 | task sourcesJar(type: Jar, dependsOn: classes) { 31 | classifier = 'sources' 32 | from sourceSets.main.allSource 33 | } 34 | 35 | task javadocJar(type: Jar, dependsOn: javadoc) { 36 | classifier = 'javadoc' 37 | from javadoc.destinationDir 38 | } 39 | 40 | artifacts { 41 | archives jar 42 | archives sourcesJar 43 | archives javadocJar 44 | } 45 | 46 | publishing { 47 | publications { 48 | maven(MavenPublication) { 49 | from components.java 50 | artifact sourcesJar 51 | artifact javadocJar 52 | groupId group 53 | artifactId project.name 54 | version project.version 55 | } 56 | } 57 | } 58 | 59 | jacoco { 60 | toolVersion = '0.8.3' 61 | } 62 | 63 | jacocoTestReport { 64 | reports { 65 | xml.enabled = true 66 | html.enabled = false 67 | } 68 | } 69 | 70 | check.dependsOn jacocoTestReport 71 | 72 | dependencyUpdates { 73 | resolutionStrategy { 74 | componentSelection { rules -> 75 | rules.all { ComponentSelection selection -> 76 | boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm', 'preview'].any { qualifier -> 77 | selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/ 78 | } 79 | if (rejected) { 80 | selection.reject('Release candidate') 81 | } 82 | } 83 | } 84 | } 85 | outputFormatter = { result -> 86 | if (!result.outdated.dependencies.isEmpty()) { 87 | throw new GradleException('Abort, there are dependencies to update.') 88 | } 89 | } 90 | } 91 | 92 | bintrayUpload.dependsOn(dependencyUpdates) 93 | bintrayUpload.dependsOn(check) 94 | 95 | task('installSharedIdea', type: Copy) { 96 | description = "Copy the shared intellij files into local .idea/" 97 | from 'ideaShared/' 98 | into '.idea/' 99 | } 100 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | buildscript { 23 | repositories { 24 | jcenter() 25 | } 26 | dependencies { 27 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' 28 | classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0' 29 | } 30 | } 31 | 32 | plugins { 33 | id 'com.github.spotbugs' version '1.6.9' 34 | } 35 | 36 | group 'io.github.novacrypto' 37 | version '2019.01.27' 38 | 39 | apply plugin: 'java' 40 | apply from: 'bintray.gradle' 41 | 42 | // Generate a dependency version update report for release 43 | // ./gradlew dependencyUpdates -Drevision=release 44 | // https://github.com/ben-manes/gradle-versions-plugin 45 | apply plugin: 'com.github.ben-manes.versions' 46 | 47 | spotbugs { 48 | toolVersion = '3.1.11' 49 | } 50 | 51 | allprojects { 52 | tasks.withType(com.github.spotbugs.SpotBugsTask) { 53 | reports { 54 | xml.enabled = false 55 | html.enabled = true 56 | } 57 | } 58 | } 59 | 60 | // To upload a new version 61 | // ./gradlew clean build bintrayUpload -Puser=user -Pkey=APIKEY 62 | bintray { 63 | user = project.ext.properties.user 64 | key = project.ext.properties.key 65 | publications = ['maven'] 66 | pkg { 67 | repo = 'BIP' 68 | name = project.name 69 | userOrg = 'novacrypto' 70 | licenses = ['GPL-3.0'] 71 | vcsUrl = "https://github.com/NovaCrypto/${project.name}.git" 72 | version { 73 | name = project.version 74 | } 75 | } 76 | } 77 | 78 | repositories { 79 | jcenter() 80 | maven { 81 | url 'https://dl.bintray.com/novacrypto/General/' 82 | } 83 | maven { 84 | url 'https://dl.bintray.com/novacrypto/Hashing/' 85 | } 86 | maven { 87 | url 'https://dl.bintray.com/novacrypto/BIP/' 88 | } 89 | } 90 | 91 | compileJava { 92 | sourceCompatibility = '1.7' 93 | targetCompatibility = '1.7' 94 | } 95 | 96 | dependencies { 97 | compile 'com.madgag.spongycastle:core:1.58.0.0@jar' 98 | compile 'io.github.novacrypto:SHA256:2019.01.27@jar' 99 | compile 'io.github.novacrypto:ToRuntime:2019.01.27@jar' 100 | testCompile 'junit:junit:4.12' 101 | testCompile 'com.google.code.gson:gson:2.8.5' 102 | testCompile 'org.assertj:assertj-core:3.11.1' 103 | testCompile 'io.github.novacrypto:BIP32:2019.01.27' 104 | } 105 | 106 | compileJava.options.encoding = 'UTF-8' 107 | compileTestJava.options.encoding = 'UTF-8' 108 | javadoc.options.encoding = 'UTF-8' 109 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Dfile.encoding=UTF-8 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NovaCrypto/BIP39/0e7fa95f80b2c60cd51ab81285239c2611d06871/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # BIP39 library, a Java implementation of BIP39 3 | # Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | # Original source: https://github.com/NovaCrypto/BIP39 19 | # You can contact the authors via github issues. 20 | # 21 | 22 | distributionBase=GRADLE_USER_HOME 23 | distributionPath=wrapper/dists 24 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip 25 | zipStoreBase=GRADLE_USER_HOME 26 | zipStorePath=wrapper/dists 27 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /ideaShared/copyright/GNU_GPLv3.xml: -------------------------------------------------------------------------------- 1 | 21 | 22 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /ideaShared/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | rootProject.name = 'BIP39' 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/AlphabeticalCharSequenceComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import java.util.Comparator; 25 | 26 | enum CharSequenceComparators implements Comparator { 27 | 28 | ALPHABETICAL { 29 | @Override 30 | public int compare(final CharSequence o1, final CharSequence o2) { 31 | final int length1 = o1.length(); 32 | final int length2 = o2.length(); 33 | final int length = Math.min(length1, length2); 34 | for (int i = 0; i < length; i++) { 35 | final int compare = Character.compare(o1.charAt(i), o2.charAt(i)); 36 | if (compare != 0) return compare; 37 | } 38 | return Integer.compare(length1, length2); 39 | } 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/ByteUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | final class ByteUtils { 25 | 26 | static int next11Bits(byte[] bytes, int offset) { 27 | final int skip = offset / 8; 28 | final int lowerBitsToRemove = (3 * 8 - 11) - (offset % 8); 29 | return (((int) bytes[skip] & 0xff) << 16 | 30 | ((int) bytes[skip + 1] & 0xff) << 8 | 31 | (lowerBitsToRemove < 8 32 | ? ((int) bytes[skip + 2] & 0xff) 33 | : 0)) >> lowerBitsToRemove & (1 << 11) - 1; 34 | } 35 | 36 | static void writeNext11(byte[] bytes, int value, int offset) { 37 | int skip = offset / 8; 38 | int bitSkip = offset % 8; 39 | {//byte 0 40 | byte firstValue = bytes[skip]; 41 | byte toWrite = (byte) (value >> (3 + bitSkip)); 42 | bytes[skip] = (byte) (firstValue | toWrite); 43 | } 44 | 45 | {//byte 1 46 | byte valueInByte = bytes[skip + 1]; 47 | final int i = 5 - bitSkip; 48 | byte toWrite = (byte) (i > 0 ? (value << i) : (value >> -i)); 49 | bytes[skip + 1] = (byte) (valueInByte | toWrite); 50 | } 51 | 52 | if (bitSkip >= 6) {//byte 2 53 | byte valueInByte = bytes[skip + 2]; 54 | byte toWrite = (byte) (value << 13 - bitSkip); 55 | bytes[skip + 2] = (byte) (valueInByte | toWrite); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/CharSequenceSplitter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import java.util.LinkedList; 25 | import java.util.List; 26 | 27 | final class CharSequenceSplitter { 28 | 29 | private final char separator1; 30 | private final char separator2; 31 | 32 | CharSequenceSplitter(final char separator1, final char separator2) { 33 | this.separator1 = separator1; 34 | this.separator2 = separator2; 35 | } 36 | 37 | List split(final CharSequence charSequence) { 38 | final LinkedList list = new LinkedList<>(); 39 | int start = 0; 40 | final int length = charSequence.length(); 41 | for (int i = 0; i < length; i++) { 42 | final char c = charSequence.charAt(i); 43 | if (c == separator1 || c == separator2) { 44 | list.add(charSequence.subSequence(start, i)); 45 | start = i + 1; 46 | } 47 | } 48 | list.add(charSequence.subSequence(start, length)); 49 | return list; 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/JavaxPBKDF2WithHmacSHA512.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import io.github.novacrypto.toruntime.CheckedExceptionToRuntime; 25 | 26 | import javax.crypto.SecretKey; 27 | import javax.crypto.SecretKeyFactory; 28 | import javax.crypto.spec.PBEKeySpec; 29 | 30 | import static io.github.novacrypto.toruntime.CheckedExceptionToRuntime.toRuntime; 31 | 32 | /** 33 | * Not available in all Java implementations, for example will not find the implementation before Android API 26+. 34 | * See https://developer.android.com/reference/javax/crypto/SecretKeyFactory.html for more details. 35 | */ 36 | public enum JavaxPBKDF2WithHmacSHA512 implements PBKDF2WithHmacSHA512 { 37 | INSTANCE; 38 | 39 | private SecretKeyFactory skf = getPbkdf2WithHmacSHA512(); 40 | 41 | @Override 42 | public byte[] hash(char[] chars, byte[] salt) { 43 | final PBEKeySpec spec = new PBEKeySpec(chars, salt, 2048, 512); 44 | final byte[] encoded = generateSecretKey(spec).getEncoded(); 45 | spec.clearPassword(); 46 | return encoded; 47 | } 48 | 49 | private SecretKey generateSecretKey(final PBEKeySpec spec) { 50 | return toRuntime(new CheckedExceptionToRuntime.Func() { 51 | @Override 52 | public SecretKey run() throws Exception { 53 | return skf.generateSecret(spec); 54 | } 55 | }); 56 | } 57 | 58 | private static SecretKeyFactory getPbkdf2WithHmacSHA512() { 59 | return toRuntime(new CheckedExceptionToRuntime.Func() { 60 | @Override 61 | public SecretKeyFactory run() throws Exception { 62 | return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512"); 63 | } 64 | }); 65 | } 66 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/MnemonicGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import java.util.Arrays; 25 | 26 | import static io.github.novacrypto.bip39.ByteUtils.next11Bits; 27 | import static io.github.novacrypto.hashing.Sha256.sha256; 28 | 29 | /** 30 | * Generates mnemonics from entropy. 31 | */ 32 | public final class MnemonicGenerator { 33 | 34 | private final WordList wordList; 35 | 36 | /** 37 | * Create a generator using the given word list. 38 | * 39 | * @param wordList A known ordered list of 2048 words to select from. 40 | */ 41 | public MnemonicGenerator(final WordList wordList) { 42 | this.wordList = wordList; 43 | } 44 | 45 | public interface Target { 46 | void append(final CharSequence string); 47 | } 48 | 49 | /** 50 | * Create a mnemonic from the word list given the entropy. 51 | * 52 | * @param entropyHex 128-256 bits of hex entropy, number of bits must also be divisible by 32 53 | * @param target Where to write the mnemonic to 54 | */ 55 | public void createMnemonic( 56 | final CharSequence entropyHex, 57 | final Target target) { 58 | final int length = entropyHex.length(); 59 | if (length % 2 != 0) 60 | throw new RuntimeException("Length of hex chars must be divisible by 2"); 61 | final byte[] entropy = new byte[length / 2]; 62 | try { 63 | for (int i = 0, j = 0; i < length; i += 2, j++) { 64 | entropy[j] = (byte) (parseHex(entropyHex.charAt(i)) << 4 | parseHex(entropyHex.charAt(i + 1))); 65 | } 66 | createMnemonic(entropy, target); 67 | } finally { 68 | Arrays.fill(entropy, (byte) 0); 69 | } 70 | } 71 | 72 | /** 73 | * Create a mnemonic from the word list given the entropy. 74 | * 75 | * @param entropy 128-256 bits of entropy, number of bits must also be divisible by 32 76 | * @param target Where to write the mnemonic to 77 | */ 78 | public void createMnemonic( 79 | final byte[] entropy, 80 | final Target target) { 81 | final int[] wordIndexes = wordIndexes(entropy); 82 | try { 83 | createMnemonic(wordIndexes, target); 84 | } finally { 85 | Arrays.fill(wordIndexes, 0); 86 | } 87 | } 88 | 89 | private void createMnemonic( 90 | final int[] wordIndexes, 91 | final Target target) { 92 | final String space = String.valueOf(wordList.getSpace()); 93 | for (int i = 0; i < wordIndexes.length; i++) { 94 | if (i > 0) target.append(space); 95 | target.append(wordList.getWord(wordIndexes[i])); 96 | } 97 | } 98 | 99 | private static int[] wordIndexes(byte[] entropy) { 100 | final int ent = entropy.length * 8; 101 | entropyLengthPreChecks(ent); 102 | 103 | final byte[] entropyWithChecksum = Arrays.copyOf(entropy, entropy.length + 1); 104 | entropyWithChecksum[entropy.length] = firstByteOfSha256(entropy); 105 | 106 | //checksum length 107 | final int cs = ent / 32; 108 | //mnemonic length 109 | final int ms = (ent + cs) / 11; 110 | 111 | //get the indexes into the word list 112 | final int[] wordIndexes = new int[ms]; 113 | for (int i = 0, wi = 0; wi < ms; i += 11, wi++) { 114 | wordIndexes[wi] = next11Bits(entropyWithChecksum, i); 115 | } 116 | return wordIndexes; 117 | } 118 | 119 | static byte firstByteOfSha256(final byte[] entropy) { 120 | final byte[] hash = sha256(entropy); 121 | final byte firstByte = hash[0]; 122 | Arrays.fill(hash, (byte) 0); 123 | return firstByte; 124 | } 125 | 126 | private static void entropyLengthPreChecks(final int ent) { 127 | if (ent < 128) 128 | throw new RuntimeException("Entropy too low, 128-256 bits allowed"); 129 | if (ent > 256) 130 | throw new RuntimeException("Entropy too high, 128-256 bits allowed"); 131 | if (ent % 32 > 0) 132 | throw new RuntimeException("Number of entropy bits must be divisible by 32"); 133 | } 134 | 135 | private static int parseHex(char c) { 136 | if (c >= '0' && c <= '9') return c - '0'; 137 | if (c >= 'a' && c <= 'f') return (c - 'a') + 10; 138 | if (c >= 'A' && c <= 'F') return (c - 'A') + 10; 139 | throw new RuntimeException("Invalid hex char '" + c + '\''); 140 | } 141 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/MnemonicValidator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import io.github.novacrypto.bip39.Validation.InvalidChecksumException; 25 | import io.github.novacrypto.bip39.Validation.InvalidWordCountException; 26 | import io.github.novacrypto.bip39.Validation.UnexpectedWhiteSpaceException; 27 | import io.github.novacrypto.bip39.Validation.WordNotFoundException; 28 | 29 | import java.util.Arrays; 30 | import java.util.Collection; 31 | import java.util.Comparator; 32 | 33 | import static io.github.novacrypto.bip39.MnemonicGenerator.firstByteOfSha256; 34 | import static io.github.novacrypto.bip39.Normalization.normalizeNFKD; 35 | 36 | /** 37 | * Contains function for validating Mnemonics against the BIP0039 spec. 38 | */ 39 | public final class MnemonicValidator { 40 | private final WordAndIndex[] words; 41 | private final CharSequenceSplitter charSequenceSplitter; 42 | private final NFKDNormalizer normalizer; 43 | 44 | private MnemonicValidator(final WordList wordList) { 45 | normalizer = new WordListMapNormalization(wordList); 46 | words = new WordAndIndex[1 << 11]; 47 | for (int i = 0; i < 1 << 11; i++) { 48 | words[i] = new WordAndIndex(i, wordList.getWord(i)); 49 | } 50 | charSequenceSplitter = new CharSequenceSplitter(wordList.getSpace(), normalizeNFKD(wordList.getSpace())); 51 | Arrays.sort(words, wordListSortOrder); 52 | } 53 | 54 | /** 55 | * Get a Mnemonic validator for the given word list. 56 | * No normalization is currently performed, this is an open issue: https://github.com/NovaCrypto/BIP39/issues/13 57 | * 58 | * @param wordList A WordList implementation 59 | * @return A validator 60 | */ 61 | public static MnemonicValidator ofWordList(final WordList wordList) { 62 | return new MnemonicValidator(wordList); 63 | } 64 | 65 | /** 66 | * Check that the supplied mnemonic fits the BIP0039 spec. 67 | * 68 | * @param mnemonic The memorable list of words 69 | * @throws InvalidChecksumException If the last bytes don't match the expected last bytes 70 | * @throws InvalidWordCountException If the number of words is not a multiple of 3, 24 or fewer 71 | * @throws WordNotFoundException If a word in the mnemonic is not present in the word list 72 | * @throws UnexpectedWhiteSpaceException Occurs if one of the supplied words is empty, e.g. a double space 73 | */ 74 | public void validate(final CharSequence mnemonic) throws 75 | InvalidChecksumException, 76 | InvalidWordCountException, 77 | WordNotFoundException, 78 | UnexpectedWhiteSpaceException { 79 | validate(charSequenceSplitter.split(mnemonic)); 80 | } 81 | 82 | /** 83 | * Check that the supplied mnemonic fits the BIP0039 spec. 84 | *

85 | * The purpose of this method overload is to avoid constructing a mnemonic String if you have gathered a list of 86 | * words from the user. 87 | * 88 | * @param mnemonic The memorable list of words 89 | * @throws InvalidChecksumException If the last bytes don't match the expected last bytes 90 | * @throws InvalidWordCountException If the number of words is not a multiple of 3, 24 or fewer 91 | * @throws WordNotFoundException If a word in the mnemonic is not present in the word list 92 | * @throws UnexpectedWhiteSpaceException Occurs if one of the supplied words is empty 93 | */ 94 | public void validate(final Collection mnemonic) throws 95 | InvalidChecksumException, 96 | InvalidWordCountException, 97 | WordNotFoundException, 98 | UnexpectedWhiteSpaceException { 99 | final int[] wordIndexes = findWordIndexes(mnemonic); 100 | try { 101 | validate(wordIndexes); 102 | } finally { 103 | Arrays.fill(wordIndexes, 0); 104 | } 105 | } 106 | 107 | private static void validate(final int[] wordIndexes) throws 108 | InvalidWordCountException, 109 | InvalidChecksumException { 110 | final int ms = wordIndexes.length; 111 | 112 | final int entPlusCs = ms * 11; 113 | final int ent = (entPlusCs * 32) / 33; 114 | final int cs = ent / 32; 115 | if (entPlusCs != ent + cs) 116 | throw new InvalidWordCountException(); 117 | final byte[] entropyWithChecksum = new byte[(entPlusCs + 7) / 8]; 118 | 119 | wordIndexesToEntropyWithCheckSum(wordIndexes, entropyWithChecksum); 120 | Arrays.fill(wordIndexes, 0); 121 | 122 | final byte[] entropy = Arrays.copyOf(entropyWithChecksum, entropyWithChecksum.length - 1); 123 | final byte lastByte = entropyWithChecksum[entropyWithChecksum.length - 1]; 124 | Arrays.fill(entropyWithChecksum, (byte) 0); 125 | 126 | final byte sha = firstByteOfSha256(entropy); 127 | 128 | final byte mask = maskOfFirstNBits(cs); 129 | 130 | if (((sha ^ lastByte) & mask) != 0) 131 | throw new InvalidChecksumException(); 132 | } 133 | 134 | private int[] findWordIndexes(final Collection split) throws 135 | UnexpectedWhiteSpaceException, 136 | WordNotFoundException { 137 | final int ms = split.size(); 138 | final int[] result = new int[ms]; 139 | int i = 0; 140 | for (final CharSequence buffer : split) { 141 | if (buffer.length() == 0) { 142 | throw new UnexpectedWhiteSpaceException(); 143 | } 144 | result[i++] = findWordIndex(buffer); 145 | } 146 | return result; 147 | } 148 | 149 | private int findWordIndex(final CharSequence buffer) throws WordNotFoundException { 150 | final WordAndIndex key = new WordAndIndex(-1, buffer); 151 | final int index = Arrays.binarySearch(words, key, wordListSortOrder); 152 | if (index < 0) { 153 | final int insertionPoint = -index - 1; 154 | int suggestion = insertionPoint == 0 ? insertionPoint : insertionPoint - 1; 155 | if (suggestion + 1 == words.length) suggestion--; 156 | throw new WordNotFoundException(buffer, words[suggestion].word, words[suggestion + 1].word); 157 | 158 | } 159 | return words[index].index; 160 | } 161 | 162 | private static void wordIndexesToEntropyWithCheckSum(final int[] wordIndexes, final byte[] entropyWithChecksum) { 163 | for (int i = 0, bi = 0; i < wordIndexes.length; i++, bi += 11) { 164 | ByteUtils.writeNext11(entropyWithChecksum, wordIndexes[i], bi); 165 | } 166 | } 167 | 168 | private static byte maskOfFirstNBits(final int n) { 169 | return (byte) ~((1 << (8 - n)) - 1); 170 | } 171 | 172 | private static final Comparator wordListSortOrder = new Comparator() { 173 | @Override 174 | public int compare(final WordAndIndex o1, final WordAndIndex o2) { 175 | return CharSequenceComparators.ALPHABETICAL.compare(o1.normalized, o2.normalized); 176 | } 177 | }; 178 | 179 | private class WordAndIndex { 180 | final CharSequence word; 181 | final String normalized; 182 | final int index; 183 | 184 | WordAndIndex(final int i, final CharSequence word) { 185 | this.word = word; 186 | normalized = normalizer.normalize(word); 187 | index = i; 188 | } 189 | } 190 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/NFKDNormalizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | public interface NFKDNormalizer { 25 | 26 | String normalize(CharSequence charSequence); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/Normalization.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import java.text.Normalizer; 25 | 26 | final class Normalization { 27 | static String normalizeNFKD(final String string) { 28 | return Normalizer.normalize(string, Normalizer.Form.NFKD); 29 | } 30 | 31 | static char normalizeNFKD(final char c) { 32 | return normalizeNFKD("" + c).charAt(0); 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/PBKDF2WithHmacSHA512.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | public interface PBKDF2WithHmacSHA512 { 25 | 26 | byte[] hash(final char[] chars, final byte[] salt); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/SeedCalculator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import io.github.novacrypto.toruntime.CheckedExceptionToRuntime; 25 | 26 | import java.util.Arrays; 27 | 28 | import static io.github.novacrypto.bip39.Normalization.normalizeNFKD; 29 | import static io.github.novacrypto.toruntime.CheckedExceptionToRuntime.toRuntime; 30 | 31 | /** 32 | * Contains function for generating seeds from a Mnemonic and Passphrase. 33 | */ 34 | public final class SeedCalculator { 35 | 36 | private final byte[] fixedSalt = getUtf8Bytes("mnemonic"); 37 | private final PBKDF2WithHmacSHA512 hashAlgorithm; 38 | 39 | public SeedCalculator(final PBKDF2WithHmacSHA512 hashAlgorithm) { 40 | this.hashAlgorithm = hashAlgorithm; 41 | } 42 | 43 | /** 44 | * Creates a seed calculator using {@link SpongyCastlePBKDF2WithHmacSHA512} which is the most compatible. 45 | * Use {@link SeedCalculator#SeedCalculator(PBKDF2WithHmacSHA512)} to supply another. 46 | */ 47 | public SeedCalculator() { 48 | this(SpongyCastlePBKDF2WithHmacSHA512.INSTANCE); 49 | } 50 | 51 | /** 52 | * Calculate the seed given a mnemonic and corresponding passphrase. 53 | * The phrase is not checked for validity here, for that use a {@link MnemonicValidator}. 54 | *

55 | * Due to normalization, these need to be {@link String}, and not {@link CharSequence}, this is an open issue: 56 | * https://github.com/NovaCrypto/BIP39/issues/7 57 | *

58 | * If you have a list of words selected from a word list, you can use {@link #withWordsFromWordList} then 59 | * {@link SeedCalculatorByWordListLookUp#calculateSeed} 60 | * 61 | * @param mnemonic The memorable list of words 62 | * @param passphrase An optional passphrase, use "" if not required 63 | * @return a seed for HD wallet generation 64 | */ 65 | public byte[] calculateSeed(final String mnemonic, final String passphrase) { 66 | final char[] chars = normalizeNFKD(mnemonic).toCharArray(); 67 | try { 68 | return calculateSeed(chars, passphrase); 69 | } finally { 70 | Arrays.fill(chars, '\0'); 71 | } 72 | } 73 | 74 | byte[] calculateSeed(final char[] mnemonicChars, final String passphrase) { 75 | final String normalizedPassphrase = normalizeNFKD(passphrase); 76 | final byte[] salt2 = getUtf8Bytes(normalizedPassphrase); 77 | final byte[] salt = combine(fixedSalt, salt2); 78 | clear(salt2); 79 | final byte[] encoded = hash(mnemonicChars, salt); 80 | clear(salt); 81 | return encoded; 82 | } 83 | 84 | public SeedCalculatorByWordListLookUp withWordsFromWordList(final WordList wordList) { 85 | return new SeedCalculatorByWordListLookUp(this, wordList); 86 | } 87 | 88 | private static byte[] combine(final byte[] array1, final byte[] array2) { 89 | final byte[] bytes = new byte[array1.length + array2.length]; 90 | System.arraycopy(array1, 0, bytes, 0, array1.length); 91 | System.arraycopy(array2, 0, bytes, array1.length, bytes.length - array1.length); 92 | return bytes; 93 | } 94 | 95 | private static void clear(final byte[] salt) { 96 | Arrays.fill(salt, (byte) 0); 97 | } 98 | 99 | private byte[] hash(final char[] chars, final byte[] salt) { 100 | return hashAlgorithm.hash(chars, salt); 101 | } 102 | 103 | private static byte[] getUtf8Bytes(final String string) { 104 | return toRuntime(new CheckedExceptionToRuntime.Func() { 105 | @Override 106 | public byte[] run() throws Exception { 107 | return string.getBytes("UTF-8"); 108 | } 109 | }); 110 | } 111 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/SeedCalculatorByWordListLookUp.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import java.util.*; 25 | 26 | public final class SeedCalculatorByWordListLookUp { 27 | private final SeedCalculator seedCalculator; 28 | private final Map map = new HashMap<>(); 29 | private final NFKDNormalizer normalizer; 30 | 31 | SeedCalculatorByWordListLookUp(final SeedCalculator seedCalculator, final WordList wordList) { 32 | this.seedCalculator = seedCalculator; 33 | normalizer = new WordListMapNormalization(wordList); 34 | for (int i = 0; i < 1 << 11; i++) { 35 | final String word = normalizer.normalize(wordList.getWord(i)); 36 | map.put(word, word.toCharArray()); 37 | } 38 | } 39 | 40 | /** 41 | * Calculate the seed given a mnemonic and corresponding passphrase. 42 | * The phrase is not checked for validity here, for that use a {@link MnemonicValidator}. 43 | *

44 | * The purpose of this method is to avoid constructing a mnemonic String if you have gathered a list of 45 | * words from the user and also to avoid having to normalize it, all words in the {@link WordList} are normalized 46 | * instead. 47 | *

48 | * Due to normalization, the passphrase still needs to be {@link String}, and not {@link CharSequence}, this is an 49 | * open issue: https://github.com/NovaCrypto/BIP39/issues/7 50 | * 51 | * @param mnemonic The memorable list of words, ideally selected from the word list that was supplied while creating this object. 52 | * @param passphrase An optional passphrase, use "" if not required 53 | * @return a seed for HD wallet generation 54 | */ 55 | public byte[] calculateSeed(final Collection mnemonic, final String passphrase) { 56 | final int words = mnemonic.size(); 57 | final char[][] chars = new char[words][]; 58 | final List toClear = new LinkedList<>(); 59 | int count = 0; 60 | int wordIndex = 0; 61 | for (final CharSequence word : mnemonic) { 62 | char[] wordChars = map.get(normalizer.normalize(word)); 63 | if (wordChars == null) { 64 | wordChars = normalizer.normalize(word).toCharArray(); 65 | toClear.add(wordChars); 66 | } 67 | chars[wordIndex++] = wordChars; 68 | count += wordChars.length; 69 | } 70 | count += words - 1; 71 | final char[] mnemonicChars = new char[count]; 72 | try { 73 | int index = 0; 74 | for (int i = 0; i < chars.length; i++) { 75 | System.arraycopy(chars[i], 0, mnemonicChars, index, chars[i].length); 76 | index += chars[i].length; 77 | if (i < chars.length - 1) { 78 | mnemonicChars[index++] = ' '; 79 | } 80 | } 81 | return seedCalculator.calculateSeed(mnemonicChars, passphrase); 82 | } finally { 83 | Arrays.fill(mnemonicChars, '\0'); 84 | Arrays.fill(chars, null); 85 | for (final char[] charsToClear : toClear) 86 | Arrays.fill(charsToClear, '\0'); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/SpongyCastlePBKDF2WithHmacSHA512.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import org.spongycastle.crypto.PBEParametersGenerator; 25 | import org.spongycastle.crypto.digests.SHA512Digest; 26 | import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; 27 | import org.spongycastle.crypto.params.KeyParameter; 28 | 29 | /** 30 | * This implementation is useful for older Java implementations, for example it is suitable for all Android API levels. 31 | */ 32 | public enum SpongyCastlePBKDF2WithHmacSHA512 implements PBKDF2WithHmacSHA512 { 33 | INSTANCE; 34 | 35 | @Override 36 | public byte[] hash(char[] chars, byte[] salt) { 37 | PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA512Digest()); 38 | generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(chars), salt, 2048); 39 | KeyParameter key = (KeyParameter) generator.generateDerivedMacParameters(512); 40 | return key.getKey(); 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/Validation/InvalidChecksumException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39.Validation; 23 | 24 | public final class InvalidChecksumException extends Exception { 25 | public InvalidChecksumException() { 26 | super("Invalid checksum"); 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/Validation/InvalidWordCountException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39.Validation; 23 | 24 | public final class InvalidWordCountException extends Exception { 25 | public InvalidWordCountException() { 26 | super("Not a correct number of words"); 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/Validation/UnexpectedWhiteSpaceException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39.Validation; 23 | 24 | public final class UnexpectedWhiteSpaceException extends Exception { 25 | public UnexpectedWhiteSpaceException() { 26 | super("Unexpected whitespace"); 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/Validation/WordNotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39.Validation; 23 | 24 | public final class WordNotFoundException extends Exception { 25 | private final CharSequence word; 26 | private final CharSequence suggestion1; 27 | private final CharSequence suggestion2; 28 | 29 | public WordNotFoundException( 30 | final CharSequence word, 31 | final CharSequence suggestion1, 32 | final CharSequence suggestion2) { 33 | super(String.format( 34 | "Word not found in word list \"%s\", suggestions \"%s\", \"%s\"", 35 | word, 36 | suggestion1, 37 | suggestion2)); 38 | this.word = word; 39 | this.suggestion1 = suggestion1; 40 | this.suggestion2 = suggestion2; 41 | } 42 | 43 | public CharSequence getWord() { 44 | return word; 45 | } 46 | 47 | public CharSequence getSuggestion1() { 48 | return suggestion1; 49 | } 50 | 51 | public CharSequence getSuggestion2() { 52 | return suggestion2; 53 | } 54 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/WordList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | public interface WordList { 25 | 26 | /** 27 | * Get a word in the word list. 28 | * 29 | * @param index Index of word in the word list [0..2047] inclusive. 30 | * @return the word from the list. 31 | */ 32 | String getWord(final int index); 33 | 34 | /** 35 | * Get the space character for this language. 36 | * 37 | * @return a whitespace character. 38 | */ 39 | char getSpace(); 40 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/WordListMapNormalization.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import java.text.Normalizer; 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | 28 | class WordListMapNormalization implements NFKDNormalizer { 29 | private final Map normalizedMap = new HashMap<>(); 30 | 31 | WordListMapNormalization(final WordList wordList) { 32 | for (int i = 0; i < 1 << 11; i++) { 33 | final String word = wordList.getWord(i); 34 | final String normalized = Normalizer.normalize(word, Normalizer.Form.NFKD); 35 | normalizedMap.put(word, normalized); 36 | normalizedMap.put(normalized, normalized); 37 | normalizedMap.put(Normalizer.normalize(word, Normalizer.Form.NFC), normalized); 38 | } 39 | } 40 | 41 | @Override 42 | public String normalize(final CharSequence charSequence) { 43 | final String normalized = normalizedMap.get(charSequence); 44 | if (normalized != null) 45 | return normalized; 46 | return Normalizer.normalize(charSequence, Normalizer.Form.NFKD); 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/java/io/github/novacrypto/bip39/Words.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | public enum Words { 25 | TWELVE(128), 26 | FIFTEEN(160), 27 | EIGHTEEN(192), 28 | TWENTY_ONE(224), 29 | TWENTY_FOUR(256); 30 | 31 | private final int bitLength; 32 | 33 | Words(int bitLength) { 34 | this.bitLength = bitLength; 35 | } 36 | 37 | public int bitLength() { 38 | return bitLength; 39 | } 40 | 41 | public int byteLength() { 42 | return bitLength / 8; 43 | } 44 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/Hex.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto; 23 | 24 | import java.math.BigInteger; 25 | 26 | public final class Hex { 27 | public static String toHex(byte[] array) { 28 | final BigInteger bi = new BigInteger(1, array); 29 | final String hex = bi.toString(16); 30 | final int paddingLength = (array.length * 2) - hex.length(); 31 | if (paddingLength > 0) { 32 | return String.format("%0" + paddingLength + "d", 0) + hex; 33 | } else { 34 | return hex; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/MnemonicGenerationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto; 23 | 24 | import io.github.novacrypto.bip39.MnemonicGenerator; 25 | import io.github.novacrypto.bip39.WordList; 26 | import io.github.novacrypto.bip39.wordlists.Spanish; 27 | import io.github.novacrypto.testjson.EnglishJson; 28 | import io.github.novacrypto.testjson.TestVector; 29 | import io.github.novacrypto.testjson.TestVectorJson; 30 | import io.github.novacrypto.bip39.wordlists.English; 31 | import io.github.novacrypto.bip39.wordlists.French; 32 | import io.github.novacrypto.bip39.wordlists.Japanese; 33 | import org.junit.Test; 34 | 35 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 36 | import static org.junit.Assert.assertEquals; 37 | 38 | public final class MnemonicGenerationTests { 39 | 40 | private static String createMnemonic(String f, WordList wordList) { 41 | final StringBuilder sb = new StringBuilder(); 42 | new MnemonicGenerator(wordList) 43 | .createMnemonic(f, sb::append); 44 | return sb.toString(); 45 | } 46 | 47 | private static String createMnemonic(byte[] f, WordList wordList) { 48 | final StringBuilder sb = new StringBuilder(); 49 | new MnemonicGenerator(wordList) 50 | .createMnemonic(f, sb::append); 51 | return sb.toString(); 52 | } 53 | 54 | @Test 55 | public void tooSmallEntropy() throws Exception { 56 | assertThatThrownBy( 57 | () -> createMnemonic(repeatString(30, "f"), English.INSTANCE)) 58 | .isInstanceOf(RuntimeException.class) 59 | .hasMessage("Entropy too low, 128-256 bits allowed"); 60 | } 61 | 62 | @Test 63 | public void tooSmallEntropyBytes() throws Exception { 64 | assertThatThrownBy( 65 | () -> createMnemonic(new byte[15], English.INSTANCE)) 66 | .isInstanceOf(RuntimeException.class) 67 | .hasMessage("Entropy too low, 128-256 bits allowed"); 68 | } 69 | 70 | @Test 71 | public void tooLargeEntropy() throws Exception { 72 | assertThatThrownBy( 73 | () -> createMnemonic(repeatString(66, "f"), English.INSTANCE)) 74 | .isInstanceOf(RuntimeException.class) 75 | .hasMessage("Entropy too high, 128-256 bits allowed"); 76 | } 77 | 78 | @Test 79 | public void tooLargeEntropyBytes() throws Exception { 80 | assertThatThrownBy( 81 | () -> createMnemonic(new byte[33], English.INSTANCE)) 82 | .isInstanceOf(RuntimeException.class) 83 | .hasMessage("Entropy too high, 128-256 bits allowed"); 84 | } 85 | 86 | @Test 87 | public void nonMultipleOf32() throws Exception { 88 | assertThatThrownBy( 89 | () -> createMnemonic(repeatString(34, "f"), English.INSTANCE)) 90 | .isInstanceOf(RuntimeException.class) 91 | .hasMessage("Number of entropy bits must be divisible by 32"); 92 | } 93 | 94 | @Test 95 | public void notHexPairs() throws Exception { 96 | assertThatThrownBy( 97 | () -> createMnemonic(repeatString(33, "f"), English.INSTANCE)) 98 | .isInstanceOf(RuntimeException.class) 99 | .hasMessage("Length of hex chars must be divisible by 2"); 100 | } 101 | 102 | @Test 103 | public void sevenFRepeated() throws Exception { 104 | assertEquals("legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", 105 | createMnemonic("7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", English.INSTANCE) 106 | ); 107 | } 108 | 109 | @Test 110 | public void eightZeroRepeated() throws Exception { 111 | assertEquals("letter advice cage absurd amount doctor acoustic avoid letter advice cage above", 112 | createMnemonic("80808080808080808080808080808080", English.INSTANCE) 113 | ); 114 | } 115 | 116 | @Test 117 | public void all_english_test_vectors() throws Exception { 118 | final EnglishJson data = EnglishJson.load(); 119 | for (final String[] testCase : data.english) { 120 | assertEquals(testCase[1], createMnemonic(testCase[0], English.INSTANCE)); 121 | } 122 | } 123 | 124 | @Test 125 | public void all_japanese_test_vectors() throws Exception { 126 | final TestVectorJson data = TestVectorJson.loadJapanese(); 127 | for (final TestVector testVector : data.vectors) { 128 | assertEquals(testVector.mnemonic, createMnemonic(testVector.entropy, Japanese.INSTANCE)); 129 | } 130 | } 131 | 132 | @Test 133 | public void all_french_test_vectors() throws Exception { 134 | final TestVectorJson data = TestVectorJson.loadFrench(); 135 | for (final TestVector testVector : data.vectors) { 136 | assertEquals(testVector.mnemonic, createMnemonic(testVector.entropy, French.INSTANCE)); 137 | } 138 | } 139 | 140 | @Test 141 | public void all_spanish_test_vectors() throws Exception { 142 | final TestVectorJson data = TestVectorJson.loadSpanish(); 143 | for (final TestVector testVector : data.vectors) { 144 | assertEquals(testVector.mnemonic, createMnemonic(testVector.entropy, Spanish.INSTANCE)); 145 | } 146 | } 147 | 148 | @Test 149 | public void upper_and_lower_case_hex_handled_the_same() throws Exception { 150 | final String hex = "0123456789abcdef0123456789abcdef"; 151 | assertEquals(createMnemonic(hex, English.INSTANCE), 152 | createMnemonic(hex.toUpperCase(), English.INSTANCE)); 153 | } 154 | 155 | @Test 156 | public void bad_hex_throws_g() throws Exception { 157 | final String hex = "0123456789abcdef0123456789abcdeg"; 158 | assertThatThrownBy( 159 | () -> createMnemonic(hex, English.INSTANCE)) 160 | .isInstanceOf(RuntimeException.class) 161 | .hasMessage("Invalid hex char 'g'"); 162 | } 163 | 164 | @Test 165 | public void bad_hex_throws_Z() throws Exception { 166 | final String hex = "0123456789abcdef0123456789abcdeZ"; 167 | assertThatThrownBy( 168 | () -> createMnemonic(hex, English.INSTANCE)) 169 | .isInstanceOf(RuntimeException.class) 170 | .hasMessage("Invalid hex char 'Z'"); 171 | } 172 | 173 | @Test 174 | public void bad_hex_throws_space() throws Exception { 175 | final String hex = "0123456789 abcdef0123456789abcde"; 176 | assertThatThrownBy( 177 | () -> createMnemonic(hex, English.INSTANCE)) 178 | .isInstanceOf(RuntimeException.class) 179 | .hasMessage("Invalid hex char ' '"); 180 | } 181 | 182 | @Test 183 | public void forFinallyCodeCoverage_createMnemonicWhenTargetThrowsException() throws Exception { 184 | assertThatThrownBy( 185 | () -> new MnemonicGenerator(English.INSTANCE) 186 | .createMnemonic(repeatString(32, "f"), 187 | (s) -> { 188 | throw new OutOfMemoryError(); 189 | })) 190 | .isInstanceOf(OutOfMemoryError.class); 191 | } 192 | 193 | private static String repeatString(int n, String repeat) { 194 | return new String(new char[n]).replace("\0", repeat); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/MnemonicGenerationWordCountTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto; 23 | 24 | import io.github.novacrypto.bip39.Words; 25 | import io.github.novacrypto.bip39.MnemonicGenerator; 26 | import io.github.novacrypto.bip39.WordList; 27 | import io.github.novacrypto.bip39.wordlists.English; 28 | import org.junit.Test; 29 | 30 | import static org.junit.Assert.assertEquals; 31 | 32 | public final class MnemonicGenerationWordCountTests { 33 | 34 | @Test 35 | public void twelveWordsBitLength() throws Exception { 36 | assertEquals(128, Words.TWELVE.bitLength()); 37 | } 38 | 39 | @Test 40 | public void twelveWords() throws Exception { 41 | assertEquals(12, countWords(Words.TWELVE)); 42 | } 43 | 44 | @Test 45 | public void fifteenWordsBitLength() throws Exception { 46 | assertEquals(160, Words.FIFTEEN.bitLength()); 47 | } 48 | 49 | @Test 50 | public void fifteenWords() throws Exception { 51 | assertEquals(15, countWords(Words.FIFTEEN)); 52 | } 53 | 54 | @Test 55 | public void eighteenWordsBitLength() throws Exception { 56 | assertEquals(192, Words.EIGHTEEN.bitLength()); 57 | } 58 | 59 | @Test 60 | public void eighteenWords() throws Exception { 61 | assertEquals(18, countWords(Words.EIGHTEEN)); 62 | } 63 | 64 | @Test 65 | public void twentyOneWordsBitLength() throws Exception { 66 | assertEquals(224, Words.TWENTY_ONE.bitLength()); 67 | } 68 | 69 | @Test 70 | public void twentyOneWords() throws Exception { 71 | assertEquals(21, countWords(Words.TWENTY_ONE)); 72 | } 73 | 74 | @Test 75 | public void twentyFourWordsBitLength() throws Exception { 76 | assertEquals(256, Words.TWENTY_FOUR.bitLength()); 77 | } 78 | 79 | @Test 80 | public void twentyFourWords() throws Exception { 81 | assertEquals(24, countWords(Words.TWENTY_FOUR)); 82 | } 83 | 84 | private static int countWords(Words words) { 85 | return createMnemonic(new byte[words.byteLength()], English.INSTANCE) 86 | .split("" + English.INSTANCE.getSpace()).length; 87 | } 88 | 89 | private static String createMnemonic(byte[] f, WordList wordList) { 90 | final StringBuilder sb = new StringBuilder(); 91 | new MnemonicGenerator(wordList) 92 | .createMnemonic(f, sb::append); 93 | return sb.toString(); 94 | } 95 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/MnemonicValidationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto; 23 | 24 | import io.github.novacrypto.bip39.MnemonicValidator; 25 | import io.github.novacrypto.bip39.Validation.InvalidChecksumException; 26 | import io.github.novacrypto.bip39.Validation.InvalidWordCountException; 27 | import io.github.novacrypto.bip39.Validation.UnexpectedWhiteSpaceException; 28 | import io.github.novacrypto.bip39.Validation.WordNotFoundException; 29 | import io.github.novacrypto.bip39.WordList; 30 | import io.github.novacrypto.bip39.wordlists.English; 31 | import io.github.novacrypto.bip39.wordlists.French; 32 | import io.github.novacrypto.bip39.wordlists.Japanese; 33 | import io.github.novacrypto.bip39.wordlists.Spanish; 34 | import io.github.novacrypto.testjson.EnglishJson; 35 | import io.github.novacrypto.testjson.TestVector; 36 | import io.github.novacrypto.testjson.TestVectorJson; 37 | import org.junit.Test; 38 | import org.junit.runner.RunWith; 39 | import org.junit.runners.Parameterized; 40 | 41 | import java.util.Arrays; 42 | import java.util.Collection; 43 | import java.util.List; 44 | import java.util.StringJoiner; 45 | import java.util.stream.Collectors; 46 | 47 | import static io.github.novacrypto.TestCharSequence.preventToString; 48 | import static io.github.novacrypto.TestCharSequence.preventToStringAndSubSequence; 49 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 50 | import static org.junit.Assert.*; 51 | 52 | @RunWith(Parameterized.class) 53 | public final class MnemonicValidationTests { 54 | 55 | private final Mode mode; 56 | 57 | enum Mode { 58 | ValidateWholeString, 59 | ValidateAsStringList 60 | } 61 | 62 | @Parameterized.Parameters 63 | public static Collection data() { 64 | return Arrays.asList(new Object[][]{ 65 | {Mode.ValidateWholeString}, 66 | {Mode.ValidateAsStringList} 67 | }); 68 | } 69 | 70 | public MnemonicValidationTests(final Mode mode) { 71 | this.mode = mode; 72 | } 73 | 74 | @Test(expected = WordNotFoundException.class) 75 | public void bad_english_word() throws Exception { 76 | try { 77 | validateExpectingBadWord( 78 | "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon alan", 79 | English.INSTANCE); 80 | } catch (WordNotFoundException e) { 81 | assertEquals("Word not found in word list \"alan\", suggestions \"aisle\", \"alarm\"", e.getMessage()); 82 | assertEquals("alan", e.getWord()); 83 | assertEquals("aisle", e.getSuggestion1()); 84 | assertEquals("alarm", e.getSuggestion2()); 85 | throw e; 86 | } 87 | } 88 | 89 | @Test(expected = WordNotFoundException.class) 90 | public void word_too_short() throws Exception { 91 | try { 92 | validateExpectingBadWord( 93 | "aero abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon alan", 94 | English.INSTANCE); 95 | } catch (WordNotFoundException e) { 96 | assertEquals("Word not found in word list \"aero\", suggestions \"advice\", \"aerobic\"", e.getMessage()); 97 | assertEquals("aero", e.getWord()); 98 | assertEquals("advice", e.getSuggestion1()); 99 | assertEquals("aerobic", e.getSuggestion2()); 100 | throw e; 101 | } 102 | } 103 | 104 | @Test(expected = WordNotFoundException.class) 105 | public void bad_english_word_alphabetically_before_all_others() throws Exception { 106 | try { 107 | validateExpectingBadWord( 108 | "aardvark abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon alan", 109 | English.INSTANCE); 110 | } catch (WordNotFoundException e) { 111 | assertEquals("Word not found in word list \"aardvark\", suggestions \"abandon\", \"ability\"", e.getMessage()); 112 | assertEquals("aardvark", e.getWord()); 113 | assertEquals("abandon", e.getSuggestion1()); 114 | assertEquals("ability", e.getSuggestion2()); 115 | throw e; 116 | } 117 | } 118 | 119 | @Test(expected = WordNotFoundException.class) 120 | public void bad_english_word_alphabetically_after_all_others() throws Exception { 121 | try { 122 | validateExpectingBadWord( 123 | "zymurgy abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon alan", 124 | English.INSTANCE); 125 | } catch (WordNotFoundException e) { 126 | assertEquals("Word not found in word list \"zymurgy\", suggestions \"zone\", \"zoo\"", e.getMessage()); 127 | assertEquals("zymurgy", e.getWord()); 128 | assertEquals("zone", e.getSuggestion1()); 129 | assertEquals("zoo", e.getSuggestion2()); 130 | throw e; 131 | } 132 | } 133 | 134 | @Test(expected = WordNotFoundException.class) 135 | public void bad_japanese_word() throws Exception { 136 | try { 137 | validateExpectingBadWord( 138 | "そつう れきだ ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかめ", 139 | Japanese.INSTANCE); 140 | } catch (WordNotFoundException e) { 141 | assertEquals("Word not found in word list \"れきだ\", suggestions \"れきし\", \"れきだい\"", e.getMessage()); 142 | assertEquals("れきだ", e.getWord()); 143 | assertEquals("れきし", e.getSuggestion1()); 144 | assertEquals("れきだい", e.getSuggestion2()); 145 | throw e; 146 | } 147 | } 148 | 149 | @Test(expected = WordNotFoundException.class) 150 | public void bad_japanese_word_normalized_behaviour() throws Exception { 151 | try { 152 | validateExpectingBadWord( 153 | "そつう れきだ ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかめ", 154 | Japanese.INSTANCE); 155 | } catch (WordNotFoundException e) { 156 | assertEquals("Word not found in word list \"れきだ\", suggestions \"れきし\", \"れきだい\"", e.getMessage()); 157 | assertEquals("れきだ", e.getWord()); 158 | assertEquals("れきし", e.getSuggestion1()); 159 | assertEquals("れきだい", e.getSuggestion2()); 160 | throw e; 161 | } 162 | } 163 | 164 | @Test(expected = InvalidWordCountException.class) 165 | public void eleven_words() throws Exception { 166 | validate("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon", 167 | English.INSTANCE); 168 | } 169 | 170 | @Test 171 | public void all_english_test_vectors() throws Exception { 172 | final EnglishJson data = EnglishJson.load(); 173 | for (final String[] testCase : data.english) { 174 | assertTrue(validate(testCase[1], English.INSTANCE)); 175 | } 176 | } 177 | 178 | @Test 179 | public void all_english_test_vectors_words_swapped() throws Exception { 180 | int testCaseCount = 0; 181 | final EnglishJson data = EnglishJson.load(); 182 | for (final String[] testCase : data.english) { 183 | final String mnemonic = swapWords(testCase[1], 0, 1, English.INSTANCE); 184 | if (mnemonic.equals(testCase[1])) continue; //word were same 185 | assertFalse(validate(mnemonic, English.INSTANCE)); 186 | testCaseCount++; 187 | } 188 | assertEquals(18, testCaseCount); 189 | } 190 | 191 | @Test 192 | public void additional_space_end_English() { 193 | if (mode == Mode.ValidateAsStringList) return; 194 | assertThatThrownBy(() -> 195 | validate("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about ", 196 | English.INSTANCE) 197 | ).isInstanceOf(UnexpectedWhiteSpaceException.class); 198 | } 199 | 200 | @Test 201 | public void additional_space_start_English() { 202 | assertThatThrownBy(() -> 203 | validate(" abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", 204 | English.INSTANCE) 205 | ).isInstanceOf(UnexpectedWhiteSpaceException.class); 206 | } 207 | 208 | @Test 209 | public void additional_space_middle_English() { 210 | assertThatThrownBy(() -> 211 | validate("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", 212 | English.INSTANCE) 213 | ).isInstanceOf(UnexpectedWhiteSpaceException.class); 214 | } 215 | 216 | @Test 217 | public void normalize_Japanese() throws Exception { 218 | assertTrue(validate("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", 219 | Japanese.INSTANCE)); 220 | } 221 | 222 | @Test 223 | public void normalize_Japanese_2() throws Exception { 224 | assertTrue(validate("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", 225 | Japanese.INSTANCE)); 226 | } 227 | 228 | @Test 229 | public void normalize_Japanese_regular_spaces() throws Exception { 230 | assertTrue(validate("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", 231 | Japanese.INSTANCE)); 232 | } 233 | 234 | private static String swapWords(String mnemonic, int index1, int index2, WordList wordList) { 235 | final String[] split = mnemonic.split(String.valueOf(wordList.getSpace())); 236 | String temp = split[index1]; 237 | split[index1] = split[index2]; 238 | split[index2] = temp; 239 | StringJoiner joiner = new StringJoiner(String.valueOf(wordList.getSpace())); 240 | for (String string : split) { 241 | joiner.add(string); 242 | } 243 | return joiner.toString(); 244 | } 245 | 246 | @Test 247 | public void all_japanese_test_vectors() throws Exception { 248 | final TestVectorJson data = TestVectorJson.loadJapanese(); 249 | for (final TestVector testVector : data.vectors) { 250 | assertTrue(validate(testVector.mnemonic, Japanese.INSTANCE)); 251 | } 252 | } 253 | 254 | @Test 255 | public void all_french_test_vectors() throws Exception { 256 | final TestVectorJson data = TestVectorJson.loadFrench(); 257 | for (final TestVector testVector : data.vectors) { 258 | assertTrue(validate(testVector.mnemonic, French.INSTANCE)); 259 | } 260 | } 261 | 262 | @Test 263 | public void all_spanish_test_vectors() throws Exception { 264 | final TestVectorJson data = TestVectorJson.loadSpanish(); 265 | for (final TestVector testVector : data.vectors) { 266 | assertTrue(validate(testVector.mnemonic, Spanish.INSTANCE)); 267 | } 268 | } 269 | 270 | @Test 271 | public void all_japanese_test_vectors_words_swapped() throws Exception { 272 | int testCaseCount = 0; 273 | final TestVectorJson data = TestVectorJson.loadJapanese(); 274 | for (final TestVector testVector : data.vectors) { 275 | final String mnemonic = swapWords(testVector.mnemonic, 1, 3, Japanese.INSTANCE); 276 | if (mnemonic.equals(testVector.mnemonic)) continue; //word were same 277 | assertFalse(validate(mnemonic, Japanese.INSTANCE)); 278 | testCaseCount++; 279 | } 280 | assertEquals(18, testCaseCount); 281 | } 282 | 283 | private enum ValidateMode { 284 | NOT_EXPECTING_BAD_WORD, 285 | EXPECTING_BAD_WORD 286 | } 287 | 288 | private boolean validate(String mnemonic, WordList wordList) throws 289 | InvalidWordCountException, 290 | WordNotFoundException, 291 | UnexpectedWhiteSpaceException { 292 | return validate(mnemonic, wordList, ValidateMode.NOT_EXPECTING_BAD_WORD); 293 | } 294 | 295 | private boolean validateExpectingBadWord(String mnemonic, WordList wordList) throws 296 | InvalidWordCountException, 297 | WordNotFoundException, 298 | UnexpectedWhiteSpaceException { 299 | return validate(mnemonic, wordList, ValidateMode.EXPECTING_BAD_WORD); 300 | } 301 | 302 | private boolean validate(String mnemonic, WordList wordList, ValidateMode validateMode) throws 303 | InvalidWordCountException, 304 | WordNotFoundException, 305 | UnexpectedWhiteSpaceException { 306 | try { 307 | switch (mode) { 308 | case ValidateWholeString: { 309 | MnemonicValidator 310 | .ofWordList(wordList) 311 | .validate(validateMode == ValidateMode.EXPECTING_BAD_WORD 312 | ? mnemonic 313 | : preventToString(mnemonic)); 314 | break; 315 | } 316 | case ValidateAsStringList: { 317 | final List words = Arrays.stream(mnemonic.split("[ \u3000]")) 318 | .map(sequence -> validateMode == ValidateMode.EXPECTING_BAD_WORD 319 | ? sequence 320 | : preventToStringAndSubSequence(sequence)) 321 | .collect(Collectors.toList()); 322 | MnemonicValidator 323 | .ofWordList(wordList) 324 | .validate(words); 325 | break; 326 | } 327 | } 328 | return true; 329 | } catch (InvalidChecksumException e) { 330 | return false; 331 | } 332 | } 333 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/Resources.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto; 23 | 24 | import com.google.gson.Gson; 25 | 26 | import java.io.BufferedReader; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.io.InputStreamReader; 30 | import java.nio.charset.StandardCharsets; 31 | import java.util.stream.Collectors; 32 | 33 | import static org.junit.Assert.assertNotNull; 34 | 35 | public final class Resources { 36 | 37 | private Resources() { 38 | } 39 | 40 | public static T loadJsonResource(final String resourceName, final Class classOfT) { 41 | try { 42 | try (final InputStream stream = ClassLoader.getSystemClassLoader().getResourceAsStream(resourceName)) { 43 | assertNotNull(stream); 44 | try (final BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { 45 | final String json = reader.lines().collect(Collectors.joining(System.lineSeparator())); 46 | return new Gson().fromJson(json, classOfT); 47 | } 48 | } 49 | } catch (final IOException e) { 50 | throw new RuntimeException(e); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/SeedCalculationFromWordListTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto; 23 | 24 | import io.github.novacrypto.bip39.JavaxPBKDF2WithHmacSHA512; 25 | import io.github.novacrypto.bip39.SeedCalculator; 26 | import io.github.novacrypto.bip39.SeedCalculatorByWordListLookUp; 27 | import io.github.novacrypto.bip39.WordList; 28 | import io.github.novacrypto.bip39.wordlists.English; 29 | import io.github.novacrypto.bip39.wordlists.French; 30 | import io.github.novacrypto.bip39.wordlists.Japanese; 31 | import io.github.novacrypto.bip39.wordlists.Spanish; 32 | import io.github.novacrypto.testjson.EnglishJson; 33 | import io.github.novacrypto.testjson.TestVector; 34 | import io.github.novacrypto.testjson.TestVectorJson; 35 | import org.junit.Test; 36 | 37 | import java.text.Normalizer; 38 | import java.util.Arrays; 39 | import java.util.Collection; 40 | import java.util.List; 41 | import java.util.stream.Collectors; 42 | 43 | import static io.github.novacrypto.Hex.toHex; 44 | import static io.github.novacrypto.TestCharSequence.preventToStringAndSubSequence; 45 | import static org.junit.Assert.assertEquals; 46 | 47 | public final class SeedCalculationFromWordListTests { 48 | 49 | @Test 50 | public void bip39_english() { 51 | assertEquals("2eea1e4d099089606b7678809be6090ccba0fca171d4ed42c550194ca8e3600cd1e5989dcca38e5f903f5c358c92e0dcaffc9e71a48ad489bb868025c907d1e1", 52 | calculateSeedHex("solar puppy hawk oxygen trip brief erase slot fossil mechanic filter voice", "")); 53 | } 54 | 55 | @Test 56 | public void bip39_english_word_not_found() { 57 | final String mnemonicWithBadWord = "solar puppies hawk oxygen trip brief erase slot fossil mechanic filter voice"; 58 | assertEquals(toHex(new SeedCalculator().calculateSeed(mnemonicWithBadWord, "")), 59 | calculateSeedHex(mnemonicWithBadWord, "", 60 | English.INSTANCE, ValidateMode.EXPECTING_BAD_WORD)); 61 | } 62 | 63 | @Test 64 | public void bip39_non_normalized_Japanese_word_not_found() { 65 | final String unNormalizedMnemonicWithBadWord = Normalizer.normalize("あおぞらAlan あいこくしん あいこくしん あいこくしん", Normalizer.Form.NFC); 66 | assertEquals(toHex(new SeedCalculator().calculateSeed(unNormalizedMnemonicWithBadWord, "")), 67 | calculateSeedHex(unNormalizedMnemonicWithBadWord, "", 68 | Japanese.INSTANCE, ValidateMode.EXPECTING_BAD_WORD)); 69 | } 70 | 71 | @Test 72 | public void bip39_english_with_passphrase() { 73 | assertEquals("36732d826f4fa483b5fe8373ef8d6aa3cb9c8fb30463d6c0063ee248afca2f87d11ebe6e75c2fb2736435994b868f8e9d4f4474c65ee05ac47aad7ef8a497846", 74 | calculateSeedHex("solar puppy hawk oxygen trip brief erase slot fossil mechanic filter voice", "CryptoIsCool")); 75 | } 76 | 77 | @Test 78 | public void all_english_test_vectors() { 79 | final EnglishJson data = EnglishJson.load(); 80 | for (final String[] testCase : data.english) { 81 | assertEquals(testCase[2], calculateSeedHex(testCase[1], "TREZOR")); 82 | } 83 | } 84 | 85 | @Test 86 | public void passphrase_normalization() { 87 | assertEquals(calculateSeedHex("solar puppy hawk oxygen trip brief erase slot fossil mechanic filter voice", "カ"), 88 | calculateSeedHex("solar puppy hawk oxygen trip brief erase slot fossil mechanic filter voice", "カ")); 89 | } 90 | 91 | @Test 92 | public void normalize_Japanese() { 93 | assertEquals("646f1a38134c556e948e6daef213609a62915ef568edb07ffa6046c87638b4b140fef2e0c6d7233af640c4a63de6d1a293288058c8ac1d113255d0504e63f301", 94 | calculateSeedHex("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", 95 | "", 96 | Japanese.INSTANCE)); 97 | } 98 | 99 | @Test 100 | public void normalize_Japanese_2() { 101 | assertEquals("646f1a38134c556e948e6daef213609a62915ef568edb07ffa6046c87638b4b140fef2e0c6d7233af640c4a63de6d1a293288058c8ac1d113255d0504e63f301", 102 | calculateSeedHex("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", 103 | "", 104 | Japanese.INSTANCE)); 105 | } 106 | 107 | @Test 108 | public void normalize_Japanese_regular_spaces() { 109 | assertEquals("646f1a38134c556e948e6daef213609a62915ef568edb07ffa6046c87638b4b140fef2e0c6d7233af640c4a63de6d1a293288058c8ac1d113255d0504e63f301", 110 | calculateSeedHex("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", 111 | "", 112 | Japanese.INSTANCE)); 113 | } 114 | 115 | @Test 116 | public void all_japanese_test_vectors() { 117 | final TestVectorJson data = TestVectorJson.loadJapanese(); 118 | for (final TestVector testVector : data.vectors) { 119 | testSeedGeneration(testVector, Japanese.INSTANCE); 120 | } 121 | } 122 | 123 | @Test 124 | public void all_french_test_vectors() { 125 | final TestVectorJson data = TestVectorJson.loadFrench(); 126 | for (final TestVector testVector : data.vectors) { 127 | testSeedGeneration(testVector, French.INSTANCE); 128 | } 129 | } 130 | 131 | @Test 132 | public void all_spanish_test_vectors() { 133 | final TestVectorJson data = TestVectorJson.loadSpanish(); 134 | for (final TestVector testVector : data.vectors) { 135 | testSeedGeneration(testVector, Spanish.INSTANCE); 136 | } 137 | } 138 | 139 | private static void testSeedGeneration(TestVector testVector, WordList wordList) { 140 | assertEquals(testVector.seed, calculateSeedHex(testVector.mnemonic, testVector.passphrase, wordList)); 141 | } 142 | 143 | private enum ValidateMode { 144 | NOT_EXPECTING_BAD_WORD, 145 | EXPECTING_BAD_WORD 146 | } 147 | 148 | private static String calculateSeedHex(final String mnemonic, String passphrase) { 149 | return calculateSeedHex(mnemonic, passphrase, ValidateMode.NOT_EXPECTING_BAD_WORD); 150 | } 151 | 152 | private static String calculateSeedHex(final String mnemonic, String passphrase, ValidateMode validateMode) { 153 | return calculateSeedHex(mnemonic, passphrase, English.INSTANCE, validateMode); 154 | } 155 | 156 | private static String calculateSeedHex(final String mnemonic, String passphrase, WordList wordList) { 157 | return calculateSeedHex(mnemonic, passphrase, wordList, ValidateMode.NOT_EXPECTING_BAD_WORD); 158 | } 159 | 160 | private static String calculateSeedHex(final String mnemonic, String passphrase, WordList wordList, ValidateMode validateMode) { 161 | final List mnemonic1 = Arrays.asList(mnemonic.split("[ \u3000]")); 162 | return calculateSeedHex(mnemonic1, passphrase, wordList, validateMode); 163 | } 164 | 165 | private static String calculateSeedHex(Collection mnemonic, String passphrase, WordList wordList, ValidateMode validateMode) { 166 | mnemonic = mnemonic.stream() 167 | .map(sequence -> 168 | validateMode == ValidateMode.EXPECTING_BAD_WORD 169 | ? sequence 170 | : preventToStringAndSubSequence(sequence)) 171 | .collect(Collectors.toList()); 172 | 173 | final String seed1 = calculateSeed(mnemonic, passphrase, new SeedCalculator() 174 | .withWordsFromWordList(wordList)); 175 | final SeedCalculatorByWordListLookUp seedCalculatorWithWords = new SeedCalculator(JavaxPBKDF2WithHmacSHA512.INSTANCE) 176 | .withWordsFromWordList(wordList); 177 | final String seed2 = calculateSeed(mnemonic, passphrase, seedCalculatorWithWords); 178 | final String seed3ForReuse = calculateSeed(mnemonic, passphrase, seedCalculatorWithWords); 179 | assertEquals(seed1, seed2); 180 | assertEquals(seed1, seed3ForReuse); 181 | return seed1; 182 | } 183 | 184 | private static String calculateSeed(Collection mnemonic, String passphrase, SeedCalculatorByWordListLookUp seedCalculator) { 185 | return toHex(seedCalculator.calculateSeed(mnemonic, passphrase)); 186 | } 187 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/SeedCalculationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto; 23 | 24 | import io.github.novacrypto.bip32.ExtendedPrivateKey; 25 | import io.github.novacrypto.bip32.networks.Bitcoin; 26 | import io.github.novacrypto.bip39.JavaxPBKDF2WithHmacSHA512; 27 | import io.github.novacrypto.bip39.SeedCalculator; 28 | import io.github.novacrypto.testjson.EnglishJson; 29 | import io.github.novacrypto.testjson.TestVector; 30 | import io.github.novacrypto.testjson.TestVectorJson; 31 | import org.junit.Test; 32 | 33 | import static io.github.novacrypto.Hex.toHex; 34 | import static org.junit.Assert.assertEquals; 35 | 36 | public final class SeedCalculationTests { 37 | 38 | @Test 39 | public void bip39_english() { 40 | assertEquals("2eea1e4d099089606b7678809be6090ccba0fca171d4ed42c550194ca8e3600cd1e5989dcca38e5f903f5c358c92e0dcaffc9e71a48ad489bb868025c907d1e1", 41 | calculateSeedHex("solar puppy hawk oxygen trip brief erase slot fossil mechanic filter voice")); 42 | } 43 | 44 | @Test 45 | public void bip39_english_with_passphrase() { 46 | assertEquals("36732d826f4fa483b5fe8373ef8d6aa3cb9c8fb30463d6c0063ee248afca2f87d11ebe6e75c2fb2736435994b868f8e9d4f4474c65ee05ac47aad7ef8a497846", 47 | calculateSeedHex("solar puppy hawk oxygen trip brief erase slot fossil mechanic filter voice", "CryptoIsCool")); 48 | } 49 | 50 | @Test 51 | public void all_english_test_vectors() { 52 | final EnglishJson data = EnglishJson.load(); 53 | for (final String[] testCase : data.english) { 54 | assertEquals(testCase[2], calculateSeedHex(testCase[1], "TREZOR")); 55 | } 56 | } 57 | 58 | @Test 59 | public void passphrase_normalization() { 60 | assertEquals(calculateSeedHex("solar puppy hawk oxygen trip brief erase slot fossil mechanic filter voice", "カ"), 61 | calculateSeedHex("solar puppy hawk oxygen trip brief erase slot fossil mechanic filter voice", "カ")); 62 | } 63 | 64 | @Test 65 | public void normalize_Japanese() { 66 | assertEquals("646f1a38134c556e948e6daef213609a62915ef568edb07ffa6046c87638b4b140fef2e0c6d7233af640c4a63de6d1a293288058c8ac1d113255d0504e63f301", 67 | calculateSeedHex("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら")); 68 | } 69 | 70 | @Test 71 | public void normalize_Japanese_2() { 72 | assertEquals("646f1a38134c556e948e6daef213609a62915ef568edb07ffa6046c87638b4b140fef2e0c6d7233af640c4a63de6d1a293288058c8ac1d113255d0504e63f301", 73 | calculateSeedHex("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら")); 74 | } 75 | 76 | @Test 77 | public void normalize_Japanese_regular_spaces() { 78 | assertEquals("646f1a38134c556e948e6daef213609a62915ef568edb07ffa6046c87638b4b140fef2e0c6d7233af640c4a63de6d1a293288058c8ac1d113255d0504e63f301", 79 | calculateSeedHex("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら")); 80 | } 81 | 82 | @Test 83 | public void all_japanese_test_vectors() { 84 | final TestVectorJson data = TestVectorJson.loadJapanese(); 85 | for (final TestVector testVector : data.vectors) { 86 | testSeedGeneration(testVector); 87 | } 88 | } 89 | 90 | @Test 91 | public void all_french_test_vectors() { 92 | final TestVectorJson data = TestVectorJson.loadFrench(); 93 | for (final TestVector testVector : data.vectors) { 94 | testSeedGeneration(testVector); 95 | } 96 | } 97 | 98 | @Test 99 | public void all_spanish_test_vectors() { 100 | final TestVectorJson data = TestVectorJson.loadSpanish(); 101 | for (final TestVector testVector : data.vectors) { 102 | testSeedGeneration(testVector); 103 | } 104 | } 105 | 106 | private static void testSeedGeneration(TestVector testVector) { 107 | final byte[] seed = new SeedCalculator().calculateSeed(testVector.mnemonic, testVector.passphrase); 108 | assertEquals(testVector.seed, toHex(seed)); 109 | assertEquals(testVector.bip32Xprv, ExtendedPrivateKey.fromSeed(seed, Bitcoin.MAIN_NET).extendedBase58()); 110 | } 111 | 112 | private static String calculateSeedHex(final String mnemonic) { 113 | return calculateSeedHex(mnemonic, ""); 114 | } 115 | 116 | private static String calculateSeedHex(String mnemonic, String passphrase) { 117 | final String seed1 = calculateSeed(mnemonic, passphrase, new SeedCalculator()); 118 | final String seed2 = calculateSeed(mnemonic, passphrase, new SeedCalculator(JavaxPBKDF2WithHmacSHA512.INSTANCE)); 119 | assertEquals(seed1, seed2); 120 | return seed1; 121 | } 122 | 123 | private static String calculateSeed(String mnemonic, String passphrase, SeedCalculator seedCalculator) { 124 | return toHex(seedCalculator.calculateSeed(mnemonic, passphrase)); 125 | } 126 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/TestCharSequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto; 23 | 24 | public final class TestCharSequence { 25 | public static CharSequence preventToStringAndSubSequence(final CharSequence sequence) { 26 | return new CharSequence() { 27 | @Override 28 | public int length() { 29 | return sequence.length(); 30 | } 31 | 32 | @Override 33 | public char charAt(int index) { 34 | return sequence.charAt(index); 35 | } 36 | 37 | @Override 38 | public boolean equals(Object obj) { 39 | return sequence.equals(obj); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return sequence.hashCode(); 45 | } 46 | 47 | @Override 48 | public CharSequence subSequence(int start, int end) { 49 | throw new RuntimeException("subSequence Not Allowed"); 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | throw new RuntimeException("toString Not Allowed"); 55 | } 56 | }; 57 | } 58 | 59 | public static CharSequence preventToString(final CharSequence sequence) { 60 | return new CharSequence() { 61 | @Override 62 | public int length() { 63 | return sequence.length(); 64 | } 65 | 66 | @Override 67 | public char charAt(int index) { 68 | return sequence.charAt(index); 69 | } 70 | 71 | @Override 72 | public boolean equals(Object obj) { 73 | return sequence.equals(obj); 74 | } 75 | 76 | @Override 77 | public int hashCode() { 78 | return sequence.hashCode(); 79 | } 80 | 81 | @Override 82 | public CharSequence subSequence(int start, int end) { 83 | return preventToString(sequence.subSequence(start, end)); 84 | } 85 | 86 | @Override 87 | public String toString() { 88 | throw new RuntimeException("toString Not Allowed"); 89 | } 90 | }; 91 | } 92 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/ValidationExceptionMessagesTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto; 23 | 24 | import io.github.novacrypto.bip39.Validation.InvalidChecksumException; 25 | import io.github.novacrypto.bip39.Validation.InvalidWordCountException; 26 | import io.github.novacrypto.bip39.Validation.UnexpectedWhiteSpaceException; 27 | import org.junit.Test; 28 | 29 | import static org.junit.Assert.assertEquals; 30 | 31 | public final class ValidationExceptionMessagesTests { 32 | 33 | @Test 34 | public void InvalidWordCountException_message() throws Exception { 35 | assertEquals("Not a correct number of words", new InvalidWordCountException().getMessage()); 36 | } 37 | 38 | @Test 39 | public void InvalidChecksumException_message() throws Exception { 40 | assertEquals("Invalid checksum", new InvalidChecksumException().getMessage()); 41 | } 42 | 43 | @Test 44 | public void UnexpectedWhiteSpaceException_message() throws Exception { 45 | assertEquals("Unexpected whitespace", new UnexpectedWhiteSpaceException().getMessage()); 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/bip39/ByteUtilTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import org.junit.Test; 25 | 26 | import static io.github.novacrypto.bip39.ByteUtils.next11Bits; 27 | import static org.junit.Assert.assertEquals; 28 | import static org.junit.Assert.assertNotNull; 29 | 30 | public final class ByteUtilTests { 31 | 32 | @Test 33 | public void forCodeCoverageOnly_create() { 34 | //noinspection ObviousNullCheck 35 | assertNotNull(new ByteUtils()); 36 | } 37 | 38 | @Test 39 | public void take11Bits() { 40 | byte[] bytes = new byte[]{(byte) 0b11111111, (byte) 0b11101111, 0b01100111, 0}; 41 | assertEquals(0b11111111111, next11Bits(bytes, 0)); 42 | assertEquals(0b11111111110, next11Bits(bytes, 1)); 43 | assertEquals(0b11101111011, next11Bits(bytes, 8)); 44 | assertEquals(0b11011110110, next11Bits(bytes, 9)); 45 | assertEquals(0b10111101100, next11Bits(bytes, 10)); 46 | assertEquals(0b01111011001, next11Bits(bytes, 11)); 47 | assertEquals(0b01100111000, next11Bits(bytes, 16)); 48 | } 49 | 50 | @Test 51 | public void take11Bits7F() { 52 | byte[] bytes = new byte[]{0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f}; 53 | assertEquals(0b01111111011, next11Bits(bytes, 0)); 54 | assertEquals(0b11111110111, next11Bits(bytes, 1)); 55 | assertEquals(0b11111101111, next11Bits(bytes, 2)); 56 | assertEquals(0b11111011111, next11Bits(bytes, 3)); 57 | assertEquals(0b11110111111, next11Bits(bytes, 4)); 58 | assertEquals(0b11101111111, next11Bits(bytes, 5)); 59 | assertEquals(0b11011111110, next11Bits(bytes, 6)); 60 | assertEquals(0b10111111101, next11Bits(bytes, 7)); 61 | assertEquals(0b01111111011, next11Bits(bytes, 8)); 62 | assertEquals(0b11111110111, next11Bits(bytes, 9)); 63 | } 64 | 65 | @Test 66 | public void take11Bits80() { 67 | byte[] bytes = new byte[]{(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80}; 68 | assertEquals(0b10000000100, next11Bits(bytes, 0)); 69 | assertEquals(0b00000001000, next11Bits(bytes, 1)); 70 | assertEquals(0b00000010000, next11Bits(bytes, 2)); 71 | assertEquals(0b00000100000, next11Bits(bytes, 3)); 72 | assertEquals(0b00001000000, next11Bits(bytes, 4)); 73 | assertEquals(0b00010000000, next11Bits(bytes, 5)); 74 | assertEquals(0b00100000001, next11Bits(bytes, 6)); 75 | assertEquals(0b01000000010, next11Bits(bytes, 7)); 76 | assertEquals(0b10000000100, next11Bits(bytes, 8)); 77 | assertEquals(0b00000001000, next11Bits(bytes, 9)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/bip39/CharSequenceSplitterTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import org.junit.Test; 25 | 26 | import java.util.List; 27 | 28 | import static org.junit.Assert.assertEquals; 29 | 30 | public final class CharSequenceSplitterTests { 31 | 32 | @Test 33 | public void empty_sequence() { 34 | final List list = new CharSequenceSplitter(' ', ' ').split(""); 35 | assertEquals(1, list.size()); 36 | assertEquals("", list.get(0).toString()); 37 | } 38 | 39 | @Test 40 | public void sequence_containing_one() { 41 | final List list = new CharSequenceSplitter(' ', ' ').split("abc"); 42 | assertEquals(1, list.size()); 43 | assertEquals("abc", list.get(0).toString()); 44 | } 45 | 46 | @Test 47 | public void two_items() { 48 | final List list = new CharSequenceSplitter(' ', ' ').split("abc def"); 49 | assertEquals(2, list.size()); 50 | assertEquals("abc", list.get(0).toString()); 51 | assertEquals("def", list.get(1).toString()); 52 | } 53 | 54 | @Test 55 | public void two_items_different_separator() { 56 | final List list = new CharSequenceSplitter('-', '-').split("abc-def"); 57 | assertEquals(2, list.size()); 58 | assertEquals("abc", list.get(0).toString()); 59 | assertEquals("def", list.get(1).toString()); 60 | } 61 | 62 | @Test 63 | public void just_separator() { 64 | final List list = new CharSequenceSplitter('-', '-').split("-"); 65 | assertEquals(2, list.size()); 66 | assertEquals("", list.get(0).toString()); 67 | assertEquals("", list.get(1).toString()); 68 | } 69 | 70 | @Test 71 | public void separator_at_end() { 72 | final List list = new CharSequenceSplitter('-', '-').split("a-b-c-"); 73 | assertEquals(4, list.size()); 74 | assertEquals("a", list.get(0).toString()); 75 | assertEquals("b", list.get(1).toString()); 76 | assertEquals("c", list.get(2).toString()); 77 | assertEquals("", list.get(3).toString()); 78 | } 79 | 80 | @Test 81 | public void two_separators_in_middle() { 82 | final List list = new CharSequenceSplitter('-', '-').split("a--b-c"); 83 | assertEquals(4, list.size()); 84 | assertEquals("a", list.get(0).toString()); 85 | assertEquals("", list.get(1).toString()); 86 | assertEquals("b", list.get(2).toString()); 87 | assertEquals("c", list.get(3).toString()); 88 | } 89 | 90 | @Test 91 | public void different_separators() { 92 | final List list = new CharSequenceSplitter('-', '+').split("a-b+c"); 93 | assertEquals(3, list.size()); 94 | assertEquals("a", list.get(0).toString()); 95 | assertEquals("b", list.get(1).toString()); 96 | assertEquals("c", list.get(2).toString()); 97 | } 98 | 99 | @Test 100 | public void whiteBox_number_of_expected_calls() { 101 | final CharSequence inner = "abc-def-123"; 102 | final Spy spy = new Spy(inner); 103 | new CharSequenceSplitter('-', '-').split(spy); 104 | assertEquals(1, spy.lengthCalls); 105 | assertEquals(inner.length(), spy.charAtCalls); 106 | assertEquals(3, spy.subSequenceCalls); 107 | assertEquals(0, spy.toStringCalls); 108 | } 109 | 110 | private static class Spy implements CharSequence { 111 | private final CharSequence inner; 112 | int lengthCalls; 113 | int charAtCalls; 114 | int subSequenceCalls; 115 | int toStringCalls; 116 | 117 | Spy(CharSequence inner) { 118 | this.inner = inner; 119 | } 120 | 121 | @Override 122 | public int length() { 123 | lengthCalls++; 124 | return inner.length(); 125 | } 126 | 127 | @Override 128 | public char charAt(int index) { 129 | charAtCalls++; 130 | return inner.charAt(index); 131 | } 132 | 133 | @Override 134 | public CharSequence subSequence(int start, int end) { 135 | subSequenceCalls++; 136 | return inner.subSequence(start, end); 137 | } 138 | 139 | @Override 140 | public String toString() { 141 | toStringCalls++; 142 | return super.toString(); 143 | } 144 | } 145 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/bip39/EnumValueValueOfCodeCoverageTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import io.github.novacrypto.bip39.wordlists.English; 25 | import io.github.novacrypto.bip39.wordlists.French; 26 | import io.github.novacrypto.bip39.wordlists.Japanese; 27 | import org.junit.Test; 28 | 29 | public final class EnumValueValueOfCodeCoverageTests { 30 | 31 | private static void superficialEnumCodeCoverage(Class> enumClass) throws Exception { 32 | for (Object o : (Object[]) enumClass.getMethod("values").invoke(null)) { 33 | enumClass.getMethod("valueOf", String.class).invoke(null, o.toString()); 34 | } 35 | } 36 | 37 | @Test 38 | public void forCodeCoverageOnly_allEnums() throws Exception { 39 | superficialEnumCodeCoverage(English.class); 40 | superficialEnumCodeCoverage(Japanese.class); 41 | superficialEnumCodeCoverage(French.class); 42 | superficialEnumCodeCoverage(CharSequenceComparators.class); 43 | superficialEnumCodeCoverage(SpongyCastlePBKDF2WithHmacSHA512.class); 44 | superficialEnumCodeCoverage(JavaxPBKDF2WithHmacSHA512.class); 45 | superficialEnumCodeCoverage(Words.class); 46 | } 47 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/bip39/NormalizationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import org.junit.Test; 25 | 26 | import static org.junit.Assert.assertNotNull; 27 | 28 | public final class NormalizationTests { 29 | 30 | @Test 31 | public void forCodeCoverageOnly_create() { 32 | //noinspection ObviousNullCheck 33 | assertNotNull(new Normalization()); 34 | } 35 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/bip39/WordListMapNormalizationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.bip39; 23 | 24 | import io.github.novacrypto.bip39.wordlists.English; 25 | import io.github.novacrypto.bip39.wordlists.French; 26 | import io.github.novacrypto.bip39.wordlists.Japanese; 27 | import io.github.novacrypto.bip39.wordlists.Spanish; 28 | import org.junit.Test; 29 | 30 | import java.text.Normalizer; 31 | import java.util.Arrays; 32 | import java.util.List; 33 | 34 | import static io.github.novacrypto.TestCharSequence.preventToStringAndSubSequence; 35 | import static org.junit.Assert.*; 36 | 37 | public final class WordListMapNormalizationTests { 38 | 39 | @Test 40 | public void given_WordList_and_get_normalized_form_returns_same_instance_twice() { 41 | final String word = Japanese.INSTANCE.getWord(2); 42 | assertWordIsNotNormalized(word); 43 | final WordListMapNormalization map = new WordListMapNormalization(Japanese.INSTANCE); 44 | final String word1 = map.normalize(word); 45 | final String word2 = map.normalize(word); 46 | assertWordIsNormalized(word1); 47 | assertSame(word1, word2); 48 | } 49 | 50 | @Test 51 | public void all_words_in_WordList_are_cached() { 52 | final WordListMapNormalization map = new WordListMapNormalization(Japanese.INSTANCE); 53 | for (int i = 0; i < 2048; i++) { 54 | final String word = Japanese.INSTANCE.getWord(i); 55 | final String word1 = map.normalize(word); 56 | final String word2 = map.normalize(word); 57 | assertWordIsNormalized(word1); 58 | assertSame(word1, word2); 59 | } 60 | } 61 | 62 | @Test 63 | public void all_normalized_words_in_WordList_are_cached() { 64 | final WordListMapNormalization map = new WordListMapNormalization(Japanese.INSTANCE); 65 | for (int i = 0; i < 2048; i++) { 66 | final String word = map.normalize(Japanese.INSTANCE.getWord(i)); 67 | final String word1 = map.normalize(word); 68 | final String word2 = map.normalize(word); 69 | assertWordIsNormalized(word1); 70 | assertSame(word1, word2); 71 | } 72 | } 73 | 74 | @Test 75 | public void all_un_normalized_words_in_WordList_are_cached() { 76 | for (WordList wordList : Arrays.asList(Japanese.INSTANCE, English.INSTANCE, French.INSTANCE, Spanish.INSTANCE)) { 77 | final WordListMapNormalization map = new WordListMapNormalization(wordList); 78 | for (int i = 0; i < 2048; i++) { 79 | final String originalWord = wordList.getWord(i); 80 | final String nfcWord = Normalizer.normalize(originalWord, Normalizer.Form.NFC); 81 | final String nfkcWord = Normalizer.normalize(originalWord, Normalizer.Form.NFKC); 82 | final String nfkdWord = Normalizer.normalize(originalWord, Normalizer.Form.NFKD); 83 | final String word1 = map.normalize(nfcWord); 84 | final String word2 = map.normalize(nfkcWord); 85 | final String word3 = map.normalize(nfkdWord); 86 | assertWordIsNormalized(word1); 87 | assertSame(word1, word2); 88 | assertSame(word1, word3); 89 | } 90 | } 91 | } 92 | 93 | @Test 94 | public void English_returns_same_word() { 95 | final WordListMapNormalization map = new WordListMapNormalization(English.INSTANCE); 96 | for (int i = 0; i < 2048; i++) { 97 | final String word = English.INSTANCE.getWord(i); 98 | final String word1 = map.normalize(word); 99 | assertWordIsNormalized(word1); 100 | assertSame(word1, word); 101 | } 102 | } 103 | 104 | @Test 105 | public void given_WordList_and_get_normalized_form_of_word_off_WordList_returns_different_instances() { 106 | final String word = Japanese.INSTANCE.getWord(2) + "X"; 107 | assertWordIsNotNormalized(word); 108 | final WordListMapNormalization map = new WordListMapNormalization(Japanese.INSTANCE); 109 | final String word1 = map.normalize(word); 110 | final String word2 = map.normalize(word); 111 | assertWordIsNormalized(word1); 112 | assertWordIsNormalized(word2); 113 | assertNotSame(word1, word2); 114 | assertEquals(word1, Normalizer.normalize(word, Normalizer.Form.NFKD)); 115 | } 116 | 117 | @Test 118 | public void does_not_call_to_string_when_in_the_dictionary() { 119 | final WordListMapNormalization map = new WordListMapNormalization(Japanese.INSTANCE); 120 | final String word = Japanese.INSTANCE.getWord(51); 121 | assertWordIsNotNormalized(word); 122 | final CharSequence wordAsSecureSequence = preventToStringAndSubSequence(word); 123 | final String word1 = map.normalize(wordAsSecureSequence); 124 | assertWordIsNormalized(word1); 125 | final String word2 = map.normalize(wordAsSecureSequence); 126 | assertSame(word1, word2); 127 | } 128 | 129 | /** 130 | * This works because the split creates char sequences with 0 hashcode 131 | */ 132 | @Test 133 | public void a_fresh_char_sequence_from_a_split_still_does_not_need_to_to_string() { 134 | final WordListMapNormalization map = new WordListMapNormalization(Japanese.INSTANCE); 135 | final String word2 = Japanese.INSTANCE.getWord(2); 136 | final String word51 = Japanese.INSTANCE.getWord(51); 137 | final String sentence = word2 + Japanese.INSTANCE.getSpace() + word51; 138 | final List split = new CharSequenceSplitter(' ', Japanese.INSTANCE.getSpace()).split(sentence); 139 | assertNotSame(split.get(0), word2); 140 | assertNotSame(split.get(1), word51); 141 | assertSame(map.normalize(word2), map.normalize(split.get(0))); 142 | assertSame(map.normalize(word51), map.normalize(split.get(1))); 143 | assertSame(map.normalize(word2), map.normalize(preventToStringAndSubSequence(split.get(0)))); 144 | assertSame(map.normalize(word51), map.normalize(preventToStringAndSubSequence(split.get(1)))); 145 | } 146 | 147 | private static void assertWordIsNotNormalized(String word) { 148 | assertFalse(isNormalized(word)); 149 | } 150 | 151 | private static void assertWordIsNormalized(String word) { 152 | assertTrue(isNormalized(word)); 153 | } 154 | 155 | private static boolean isNormalized(String word) { 156 | return Normalizer.isNormalized(word, Normalizer.Form.NFKD); 157 | } 158 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/testjson/EnglishJson.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.testjson; 23 | 24 | import io.github.novacrypto.Resources; 25 | 26 | import static org.junit.Assert.assertEquals; 27 | 28 | public final class EnglishJson { 29 | public String[][] english; 30 | 31 | public static EnglishJson load() { 32 | final EnglishJson data = Resources.loadJsonResource("bip39_english_test_vectors.json", EnglishJson.class); 33 | assertEquals(24, data.english.length); 34 | return data; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/testjson/TestVector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.testjson; 23 | 24 | import com.google.gson.annotations.SerializedName; 25 | 26 | public final class TestVector { 27 | 28 | @SerializedName("mnemonic") 29 | public String mnemonic; 30 | 31 | @SerializedName("passphrase") 32 | public String passphrase; 33 | 34 | @SerializedName("seed") 35 | public String seed; 36 | 37 | @SerializedName("entropy") 38 | public String entropy; 39 | 40 | @SerializedName("bip32_xprv") 41 | public String bip32Xprv; 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/testjson/TestVectorJson.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.testjson; 23 | 24 | import com.google.gson.annotations.SerializedName; 25 | import io.github.novacrypto.Resources; 26 | 27 | import static org.junit.Assert.assertEquals; 28 | 29 | public final class TestVectorJson { 30 | @SerializedName("data") 31 | public TestVector[] vectors; 32 | 33 | public static TestVectorJson loadJapanese() { 34 | final TestVectorJson data = Resources.loadJsonResource("bip39_japanese_test_vectors.json", TestVectorJson.class); 35 | assertEquals(24, data.vectors.length); 36 | return data; 37 | } 38 | 39 | public static TestVectorJson loadFrench() { 40 | final TestVectorJson data = Resources.loadJsonResource("bip39_french_test_vectors.json", TestVectorJson.class); 41 | assertEquals(18, data.vectors.length); 42 | return data; 43 | } 44 | 45 | public static TestVectorJson loadSpanish() { 46 | final TestVectorJson data = Resources.loadJsonResource("bip39_spanish_test_vectors.json", TestVectorJson.class); 47 | assertEquals(18, data.vectors.length); 48 | return data; 49 | } 50 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/wordlists/EnglishListContentTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.wordlists; 23 | 24 | import io.github.novacrypto.bip39.WordList; 25 | import io.github.novacrypto.bip39.wordlists.English; 26 | import org.junit.Test; 27 | 28 | import static io.github.novacrypto.wordlists.WordListHashing.WORD_COUNT; 29 | import static org.junit.Assert.assertEquals; 30 | 31 | public final class EnglishListContentTests { 32 | 33 | private final WordList wordList = English.INSTANCE; 34 | 35 | @Test 36 | public void hashCheck() { 37 | assertEquals("ffbc2f3228ee610ad011ff9d38a1fb8e49e23fb60601aa7605733abb0005b01e", 38 | WordListHashing.hashWordList(wordList)); 39 | } 40 | 41 | @Test 42 | public void normalizedHashCheck() { 43 | assertEquals("ffbc2f3228ee610ad011ff9d38a1fb8e49e23fb60601aa7605733abb0005b01e", 44 | WordListHashing.hashWordListNormalized(wordList)); 45 | } 46 | 47 | @SuppressWarnings("ResultOfMethodCallIgnored") 48 | @Test(expected = ArrayIndexOutOfBoundsException.class) 49 | public void correctNumberOfWords() { 50 | wordList.getWord(WORD_COUNT + 1); 51 | } 52 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/wordlists/FrenchListContentTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.wordlists; 23 | 24 | import io.github.novacrypto.bip39.WordList; 25 | import io.github.novacrypto.bip39.wordlists.French; 26 | import org.junit.Test; 27 | 28 | import static io.github.novacrypto.wordlists.WordListHashing.WORD_COUNT; 29 | import static org.junit.Assert.assertEquals; 30 | 31 | public final class FrenchListContentTests { 32 | private final WordList wordList = French.INSTANCE; 33 | 34 | @Test 35 | public void hashCheck() { 36 | assertEquals("9e515b24c9bb0119eaf18acf85a8303c4b8fec82dac53ad688e20f379de1286c", 37 | WordListHashing.hashWordList(wordList)); 38 | } 39 | 40 | @Test 41 | public void normalizedHashCheck() { 42 | assertEquals("922939bd934c6128a897ad299de471bd7aafe578d28a37370e881dc998903d51", 43 | WordListHashing.hashWordListNormalized(wordList)); 44 | } 45 | 46 | @SuppressWarnings("ResultOfMethodCallIgnored") 47 | @Test(expected = ArrayIndexOutOfBoundsException.class) 48 | public void correctNumberOfWords() { 49 | wordList.getWord(WORD_COUNT + 1); 50 | } 51 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/wordlists/JapaneseListContentTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.wordlists; 23 | 24 | import io.github.novacrypto.bip39.WordList; 25 | import io.github.novacrypto.bip39.wordlists.Japanese; 26 | import org.junit.Test; 27 | 28 | import static io.github.novacrypto.wordlists.WordListHashing.WORD_COUNT; 29 | import static org.junit.Assert.assertEquals; 30 | 31 | public final class JapaneseListContentTests { 32 | 33 | private final WordList wordList = Japanese.INSTANCE; 34 | 35 | @Test 36 | public void hashCheck() { 37 | assertEquals("2f61e05f096d93378a25071de9238ef2ce8d12d773a75640a3a881797e9e2148", 38 | WordListHashing.hashWordList(wordList)); 39 | } 40 | 41 | @Test 42 | public void normalizedHashCheck() { 43 | assertEquals("b20ee3499703a2a0e02ba886edc61363ce380989a8212aaf1866e5bdc6b60c61", 44 | WordListHashing.hashWordListNormalized(wordList)); 45 | } 46 | 47 | @SuppressWarnings("ResultOfMethodCallIgnored") 48 | @Test(expected = ArrayIndexOutOfBoundsException.class) 49 | public void correctNumberOfWords() { 50 | wordList.getWord(WORD_COUNT + 1); 51 | } 52 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/wordlists/SpanishListContentTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.wordlists; 23 | 24 | import io.github.novacrypto.bip39.WordList; 25 | import io.github.novacrypto.bip39.wordlists.Spanish; 26 | import org.junit.Test; 27 | 28 | import static io.github.novacrypto.wordlists.WordListHashing.WORD_COUNT; 29 | import static org.junit.Assert.assertEquals; 30 | 31 | public final class SpanishListContentTests { 32 | 33 | private final WordList wordList = Spanish.INSTANCE; 34 | 35 | @Test 36 | public void hashCheck() { 37 | assertEquals("134e8bfaf106863a7f10c04bdf922e15bbce43c30c6558c8537199d7c09ea0b2", 38 | WordListHashing.hashWordList(wordList)); 39 | } 40 | 41 | @Test 42 | public void normalizedHashCheck() { 43 | assertEquals("134e8bfaf106863a7f10c04bdf922e15bbce43c30c6558c8537199d7c09ea0b2", 44 | WordListHashing.hashWordListNormalized(wordList)); 45 | } 46 | 47 | @SuppressWarnings("ResultOfMethodCallIgnored") 48 | @Test(expected = ArrayIndexOutOfBoundsException.class) 49 | public void correctNumberOfWords() { 50 | wordList.getWord(WORD_COUNT + 1); 51 | } 52 | } -------------------------------------------------------------------------------- /src/test/java/io/github/novacrypto/wordlists/WordListHashing.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BIP39 library, a Java implementation of BIP39 3 | * Copyright (C) 2017-2019 Alan Evans, NovaCrypto 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Original source: https://github.com/NovaCrypto/BIP39 19 | * You can contact the authors via github issues. 20 | */ 21 | 22 | package io.github.novacrypto.wordlists; 23 | 24 | import io.github.novacrypto.bip39.WordList; 25 | 26 | import java.nio.charset.StandardCharsets; 27 | import java.security.MessageDigest; 28 | import java.text.Normalizer; 29 | 30 | import static io.github.novacrypto.Hex.toHex; 31 | import static io.github.novacrypto.toruntime.CheckedExceptionToRuntime.toRuntime; 32 | 33 | final class WordListHashing { 34 | 35 | static final int WORD_COUNT = 2048; 36 | 37 | static String hashWordList(final WordList wordList) { 38 | final MessageDigest digest = toRuntime(() -> MessageDigest.getInstance("SHA-256")); 39 | for (int i = 0; i < WORD_COUNT; i++) { 40 | digest.update((wordList.getWord(i) + "\n").getBytes(StandardCharsets.UTF_8)); 41 | } 42 | digest.update(("" + wordList.getSpace()).getBytes(StandardCharsets.UTF_8)); 43 | return toHex(digest.digest()); 44 | } 45 | 46 | static String hashWordListNormalized(final WordList wordList) { 47 | return hashWordList(normalizeNFKD(wordList)); 48 | } 49 | 50 | private static WordList normalizeNFKD(WordList wordList) { 51 | return new WordList() { 52 | @Override 53 | public String getWord(int index) { 54 | return Normalizer.normalize(wordList.getWord(index), Normalizer.Form.NFKD); 55 | } 56 | 57 | @Override 58 | public char getSpace() { 59 | return wordList.getSpace(); 60 | } 61 | }; 62 | } 63 | } -------------------------------------------------------------------------------- /src/test/resources/bip39_english_test_vectors.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": "https://github.com/trezor/python-mnemonic/blob/master/vectors.json", 3 | "english": [ 4 | [ 5 | "00000000000000000000000000000000", 6 | "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", 7 | "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04", 8 | "xprv9s21ZrQH143K3h3fDYiay8mocZ3afhfULfb5GX8kCBdno77K4HiA15Tg23wpbeF1pLfs1c5SPmYHrEpTuuRhxMwvKDwqdKiGJS9XFKzUsAF" 9 | ], 10 | [ 11 | "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 12 | "legal winner thank year wave sausage worth useful legal winner thank yellow", 13 | "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607", 14 | "xprv9s21ZrQH143K2gA81bYFHqU68xz1cX2APaSq5tt6MFSLeXnCKV1RVUJt9FWNTbrrryem4ZckN8k4Ls1H6nwdvDTvnV7zEXs2HgPezuVccsq" 15 | ], 16 | [ 17 | "80808080808080808080808080808080", 18 | "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", 19 | "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8", 20 | "xprv9s21ZrQH143K2shfP28KM3nr5Ap1SXjz8gc2rAqqMEynmjt6o1qboCDpxckqXavCwdnYds6yBHZGKHv7ef2eTXy461PXUjBFQg6PrwY4Gzq" 21 | ], 22 | [ 23 | "ffffffffffffffffffffffffffffffff", 24 | "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", 25 | "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069", 26 | "xprv9s21ZrQH143K2V4oox4M8Zmhi2Fjx5XK4Lf7GKRvPSgydU3mjZuKGCTg7UPiBUD7ydVPvSLtg9hjp7MQTYsW67rZHAXeccqYqrsx8LcXnyd" 27 | ], 28 | [ 29 | "000000000000000000000000000000000000000000000000", 30 | "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", 31 | "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa", 32 | "xprv9s21ZrQH143K3mEDrypcZ2usWqFgzKB6jBBx9B6GfC7fu26X6hPRzVjzkqkPvDqp6g5eypdk6cyhGnBngbjeHTe4LsuLG1cCmKJka5SMkmU" 33 | ], 34 | [ 35 | "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 36 | "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", 37 | "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd", 38 | "xprv9s21ZrQH143K3Lv9MZLj16np5GzLe7tDKQfVusBni7toqJGcnKRtHSxUwbKUyUWiwpK55g1DUSsw76TF1T93VT4gz4wt5RM23pkaQLnvBh7" 39 | ], 40 | [ 41 | "808080808080808080808080808080808080808080808080", 42 | "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", 43 | "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65", 44 | "xprv9s21ZrQH143K3VPCbxbUtpkh9pRG371UCLDz3BjceqP1jz7XZsQ5EnNkYAEkfeZp62cDNj13ZTEVG1TEro9sZ9grfRmcYWLBhCocViKEJae" 45 | ], 46 | [ 47 | "ffffffffffffffffffffffffffffffffffffffffffffffff", 48 | "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", 49 | "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528", 50 | "xprv9s21ZrQH143K36Ao5jHRVhFGDbLP6FCx8BEEmpru77ef3bmA928BxsqvVM27WnvvyfWywiFN8K6yToqMaGYfzS6Db1EHAXT5TuyCLBXUfdm" 51 | ], 52 | [ 53 | "0000000000000000000000000000000000000000000000000000000000000000", 54 | "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", 55 | "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8", 56 | "xprv9s21ZrQH143K32qBagUJAMU2LsHg3ka7jqMcV98Y7gVeVyNStwYS3U7yVVoDZ4btbRNf4h6ibWpY22iRmXq35qgLs79f312g2kj5539ebPM" 57 | ], 58 | [ 59 | "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 60 | "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", 61 | "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87", 62 | "xprv9s21ZrQH143K3Y1sd2XVu9wtqxJRvybCfAetjUrMMco6r3v9qZTBeXiBZkS8JxWbcGJZyio8TrZtm6pkbzG8SYt1sxwNLh3Wx7to5pgiVFU" 63 | ], 64 | [ 65 | "8080808080808080808080808080808080808080808080808080808080808080", 66 | "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", 67 | "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f", 68 | "xprv9s21ZrQH143K3CSnQNYC3MqAAqHwxeTLhDbhF43A4ss4ciWNmCY9zQGvAKUSqVUf2vPHBTSE1rB2pg4avopqSiLVzXEU8KziNnVPauTqLRo" 69 | ], 70 | [ 71 | "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 72 | "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", 73 | "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad", 74 | "xprv9s21ZrQH143K2WFF16X85T2QCpndrGwx6GueB72Zf3AHwHJaknRXNF37ZmDrtHrrLSHvbuRejXcnYxoZKvRquTPyp2JiNG3XcjQyzSEgqCB" 75 | ], 76 | [ 77 | "9e885d952ad362caeb4efe34a8e91bd2", 78 | "ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic", 79 | "274ddc525802f7c828d8ef7ddbcdc5304e87ac3535913611fbbfa986d0c9e5476c91689f9c8a54fd55bd38606aa6a8595ad213d4c9c9f9aca3fb217069a41028", 80 | "xprv9s21ZrQH143K2oZ9stBYpoaZ2ktHj7jLz7iMqpgg1En8kKFTXJHsjxry1JbKH19YrDTicVwKPehFKTbmaxgVEc5TpHdS1aYhB2s9aFJBeJH" 81 | ], 82 | [ 83 | "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", 84 | "gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog", 85 | "628c3827a8823298ee685db84f55caa34b5cc195a778e52d45f59bcf75aba68e4d7590e101dc414bc1bbd5737666fbbef35d1f1903953b66624f910feef245ac", 86 | "xprv9s21ZrQH143K3uT8eQowUjsxrmsA9YUuQQK1RLqFufzybxD6DH6gPY7NjJ5G3EPHjsWDrs9iivSbmvjc9DQJbJGatfa9pv4MZ3wjr8qWPAK" 87 | ], 88 | [ 89 | "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", 90 | "hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length", 91 | "64c87cde7e12ecf6704ab95bb1408bef047c22db4cc7491c4271d170a1b213d20b385bc1588d9c7b38f1b39d415665b8a9030c9ec653d75e65f847d8fc1fc440", 92 | "xprv9s21ZrQH143K2XTAhys3pMNcGn261Fi5Ta2Pw8PwaVPhg3D8DWkzWQwjTJfskj8ofb81i9NP2cUNKxwjueJHHMQAnxtivTA75uUFqPFeWzk" 93 | ], 94 | [ 95 | "c0ba5a8e914111210f2bd131f3d5e08d", 96 | "scheme spot photo card baby mountain device kick cradle pact join borrow", 97 | "ea725895aaae8d4c1cf682c1bfd2d358d52ed9f0f0591131b559e2724bb234fca05aa9c02c57407e04ee9dc3b454aa63fbff483a8b11de949624b9f1831a9612", 98 | "xprv9s21ZrQH143K3FperxDp8vFsFycKCRcJGAFmcV7umQmcnMZaLtZRt13QJDsoS5F6oYT6BB4sS6zmTmyQAEkJKxJ7yByDNtRe5asP2jFGhT6" 99 | ], 100 | [ 101 | "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", 102 | "horn tenant knee talent sponsor spell gate clip pulse soap slush warm silver nephew swap uncle crack brave", 103 | "fd579828af3da1d32544ce4db5c73d53fc8acc4ddb1e3b251a31179cdb71e853c56d2fcb11aed39898ce6c34b10b5382772db8796e52837b54468aeb312cfc3d", 104 | "xprv9s21ZrQH143K3R1SfVZZLtVbXEB9ryVxmVtVMsMwmEyEvgXN6Q84LKkLRmf4ST6QrLeBm3jQsb9gx1uo23TS7vo3vAkZGZz71uuLCcywUkt" 105 | ], 106 | [ 107 | "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", 108 | "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside", 109 | "72be8e052fc4919d2adf28d5306b5474b0069df35b02303de8c1729c9538dbb6fc2d731d5f832193cd9fb6aeecbc469594a70e3dd50811b5067f3b88b28c3e8d", 110 | "xprv9s21ZrQH143K2WNnKmssvZYM96VAr47iHUQUTUyUXH3sAGNjhJANddnhw3i3y3pBbRAVk5M5qUGFr4rHbEWwXgX4qrvrceifCYQJbbFDems" 111 | ], 112 | [ 113 | "23db8160a31d3e0dca3688ed941adbf3", 114 | "cat swing flag economy stadium alone churn speed unique patch report train", 115 | "deb5f45449e615feff5640f2e49f933ff51895de3b4381832b3139941c57b59205a42480c52175b6efcffaa58a2503887c1e8b363a707256bdd2b587b46541f5", 116 | "xprv9s21ZrQH143K4G28omGMogEoYgDQuigBo8AFHAGDaJdqQ99QKMQ5J6fYTMfANTJy6xBmhvsNZ1CJzRZ64PWbnTFUn6CDV2FxoMDLXdk95DQ" 117 | ], 118 | [ 119 | "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", 120 | "light rule cinnamon wrap drastic word pride squirrel upgrade then income fatal apart sustain crack supply proud access", 121 | "4cbdff1ca2db800fd61cae72a57475fdc6bab03e441fd63f96dabd1f183ef5b782925f00105f318309a7e9c3ea6967c7801e46c8a58082674c860a37b93eda02", 122 | "xprv9s21ZrQH143K3wtsvY8L2aZyxkiWULZH4vyQE5XkHTXkmx8gHo6RUEfH3Jyr6NwkJhvano7Xb2o6UqFKWHVo5scE31SGDCAUsgVhiUuUDyh" 123 | ], 124 | [ 125 | "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", 126 | "all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform", 127 | "26e975ec644423f4a4c4f4215ef09b4bd7ef924e85d1d17c4cf3f136c2863cf6df0a475045652c57eb5fb41513ca2a2d67722b77e954b4b3fc11f7590449191d", 128 | "xprv9s21ZrQH143K3rEfqSM4QZRVmiMuSWY9wugscmaCjYja3SbUD3KPEB1a7QXJoajyR2T1SiXU7rFVRXMV9XdYVSZe7JoUXdP4SRHTxsT1nzm" 129 | ], 130 | [ 131 | "f30f8c1da665478f49b001d94c5fc452", 132 | "vessel ladder alter error federal sibling chat ability sun glass valve picture", 133 | "2aaa9242daafcee6aa9d7269f17d4efe271e1b9a529178d7dc139cd18747090bf9d60295d0ce74309a78852a9caadf0af48aae1c6253839624076224374bc63f", 134 | "xprv9s21ZrQH143K2QWV9Wn8Vvs6jbqfF1YbTCdURQW9dLFKDovpKaKrqS3SEWsXCu6ZNky9PSAENg6c9AQYHcg4PjopRGGKmdD313ZHszymnps" 135 | ], 136 | [ 137 | "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", 138 | "scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump", 139 | "7b4a10be9d98e6cba265566db7f136718e1398c71cb581e1b2f464cac1ceedf4f3e274dc270003c670ad8d02c4558b2f8e39edea2775c9e232c7cb798b069e88", 140 | "xprv9s21ZrQH143K4aERa2bq7559eMCCEs2QmmqVjUuzfy5eAeDX4mqZffkYwpzGQRE2YEEeLVRoH4CSHxianrFaVnMN2RYaPUZJhJx8S5j6puX" 141 | ], 142 | [ 143 | "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", 144 | "void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold", 145 | "01f5bced59dec48e362f2c45b5de68b9fd6c92c6634f44d6d40aab69056506f0e35524a518034ddc1192e1dacd32c1ed3eaa3c3b131c88ed8e7e54c49a5d0998", 146 | "xprv9s21ZrQH143K39rnQJknpH1WEPFJrzmAqqasiDcVrNuk926oizzJDDQkdiTvNPr2FYDYzWgiMiC63YmfPAa2oPyNB23r2g7d1yiK6WpqaQS" 147 | ] 148 | ] 149 | } -------------------------------------------------------------------------------- /src/test/resources/bip39_french_test_vectors.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": "https://iancoleman.github.io/bip39/#french", 3 | "data": [ 4 | { 5 | "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 6 | "mnemonic": "implorer visage sonnette voyage véloce pourpre volaille tribunal implorer visage sonnette voyelle", 7 | "passphrase": "TREZOR", 8 | "seed": "ab9180b7dfdde74e5cf8781e5692e2c0b55afa8bc1987fa8e14e3fb83c88b195c53e9f939f8febc33d2958f5fcd8add57843cb318d8886130ef9c9879c826357", 9 | "bip32_xprv": "xprv9s21ZrQH143K3MCzhsD85FFZ2d8vDN2QdRTN63gbU3qHjZxn7utU1kwYGR5bxQkssS1Tji4Tuw8vpTzDWogXxhbWYDKuZveeRBe5wiNsuFJ" 10 | }, 11 | { 12 | "entropy": "ffffffffffffffffffffffffffffffff", 13 | "mnemonic": "zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie voter", 14 | "passphrase": "TREZOR", 15 | "seed": "7d2f168ce71ba3e40e74baf47a072a94e49973c0dbdb33a62b3a285ab167c704a85d6ce0d15cc6a4dd3bf1311334ee0d290ae7d20115863d5f5633b8dfacf2d4", 16 | "bip32_xprv": "xprv9s21ZrQH143K2AsqW9AAdu5C4zUaV45MgyzBQAYbEKtKusR83UzLwCZdqDwqJ59ebNryoNuVA5pEiY1eBYqr64UGkwZGezwaceCqxPWia7M" 17 | }, 18 | { 19 | "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 20 | "mnemonic": "implorer visage sonnette voyage véloce pourpre volaille tribunal implorer visage sonnette voyage véloce pourpre volaille tribunal implorer vinaigre", 21 | "passphrase": "TREZOR", 22 | "seed": "dcf42783150cdb92672c9ea7d13f145401661f10b89bfb012a803ca7713e97181ee28ac327a982060a7f8aaa6e8c649ca2c5b83c24458393fe41739ced31d987", 23 | "bip32_xprv": "xprv9s21ZrQH143K2Lq1fbvL5nedyALbSBmmm4EbcVduaPFArtunM6azzNy96pcKbLvVBQcFFDa3Agp54eMhCBH5Ehtbxitv525n2SrhYvALPiD" 24 | }, 25 | { 26 | "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffff", 27 | "mnemonic": "zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie viande", 28 | "passphrase": "TREZOR", 29 | "seed": "e12d20a535ef5e9e2f87e05b5261bdb51451e052fe484feb87543f5cb7a8822c4aa0152492be1259fba00a28c1e95518a90f0645bdd0eb822516d37ac881f7e0", 30 | "bip32_xprv": "xprv9s21ZrQH143K2woSZYBmSoRYygWNGUUrkLiy2i4FmReSqyc568kb1siagkBpHFj6MzLbfuh8TaWKDckfnfphrYyKTAG2rk5y4sGv4fjn5gD" 31 | }, 32 | { 33 | "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 34 | "mnemonic": "implorer visage sonnette voyage véloce pourpre volaille tribunal implorer visage sonnette voyage véloce pourpre volaille tribunal implorer visage sonnette voyage véloce pourpre volaille studieux", 35 | "passphrase": "TREZOR", 36 | "seed": "8f12b35fe92a7586dfbdab9721a91300d0dbe3185d0943021667e62fd5a643e0cf2443e544738c5234009aa50faac0dbb123ac847c31dc25d875c56fe39c6186", 37 | "bip32_xprv": "xprv9s21ZrQH143K43qySSryByKtU1Df5foSz6kDEHUsR524HZJzxnKrrU3wTdeSvHVvpitC8nAb2kdeVWGREu22KaiaMF3YjEZQdb7htpY6CXP" 38 | }, 39 | { 40 | "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 41 | "mnemonic": "zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie valable", 42 | "passphrase": "TREZOR", 43 | "seed": "b5e96f552ba44ec827c1bc5ef362e8cea68dd6f36f2c8640aeb171cf9b66198fbdf155fdbcf7dc505431068f972a92442f33cda0065afc1e9a7f5f7097ea6c6a", 44 | "bip32_xprv": "xprv9s21ZrQH143K2umcmDhRrUZ8wsZ7ACj6rvFCEuDK1coHWpo1RwYPvy3dpWmvPjstSMm9fm3igm9gjsAesjqAU6Tnejizy919FSmyofhRTyS" 45 | }, 46 | { 47 | "entropy": "77c2b00716cec7213839159e404db50d", 48 | "mnemonic": "gyrostat aurore absolu chagrin tomate logique soulever brave monstre acajou frisson berger", 49 | "passphrase": "TREZOR", 50 | "seed": "f4988154e66df3c9ab667914237e87ef809a90f2006e668e596e578d130b357992d64da7f44dbf07754295c9ec3fcfff0ca23988bfacc5b45a7fe7f8c98e55b1", 51 | "bip32_xprv": "xprv9s21ZrQH143K4Vr7qo2KQ8YsgSZ7CWURK2KRMWHEn3nYdPo12YSbo1dwP99XLhEAJgTyy8U4kHx4gXksSKFTE1uoacrSqSxFnkrYLqThbgm" 52 | }, 53 | { 54 | "entropy": "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", 55 | "mnemonic": "pénurie sagesse averse écrivain favori vertu brique halte accolade amorcer ratisser enfermer inoculer ivoire vanille sceptre tremper serrure", 56 | "passphrase": "TREZOR", 57 | "seed": "60355a67adab6b7a275cf123df17d47a884db365373eefff9d62d734048fe86ecec162bffe6e2db0b937788e4fda49144557cb02251c42a13c99628bac068823", 58 | "bip32_xprv": "xprv9s21ZrQH143K3dhNTe5wABNgAUSYZWNoC1gc6e5NxGnZ5KjYZV25Msnd84iUZ6CQWvV1e6M9DkoXq9sanF4oPd5kzynKtsn1of8dDDWRYTT" 59 | }, 60 | { 61 | "entropy": "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", 62 | "mnemonic": "daigner murmure innocent globe luxueux sérieux nuptial priver résoudre subtil imiter négation loutre cruel fruit suffixe cirque dépenser ruban accabler quotient décaler buvette élégant", 63 | "passphrase": "TREZOR", 64 | "seed": "3237424feb4554afe9edea53de59ccead07feaef29638523b3408bbd33c97e6cf9ce86313d41aebe3c487d6135b4a3161b2d54623839e5321ca3f455828084ab", 65 | "bip32_xprv": "xprv9s21ZrQH143K3LsqcnWZXzeK9mrMRZUyDeQxtnyQAPdXyto68t1fWAHR5UmdYWyZtQgBHwji9vEnuSMAHHFuzxAB139kfq2HnMJbrdvHxAN" 66 | }, 67 | { 68 | "entropy": "0460ef47585604c5660618db2e6a7e7f", 69 | "mnemonic": "acteur agacer roseau palourde exiler famille méchant prospère sérieux golfeur moufle voyelle", 70 | "passphrase": "TREZOR", 71 | "seed": "2a6fce53b3f22341c24136ed86e86810410b3ce2590f021f2a90303ef0680373e8dff00f0ccadd0c8545421e64dc44001b5aa5b50eea0ded9b94b149837b1647", 72 | "bip32_xprv": "xprv9s21ZrQH143K2Qr4ogkmy4m9bRhnCxPiBT2bMKArBjA8fSzyuLhs8phoGnM5rVsi5LJGs7qBmxD65FNFTFtprW7hZA83ZSwVyqTQ9v6gF4D" 73 | }, 74 | { 75 | "entropy": "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", 76 | "mnemonic": "globe palace osciller lapin sécable fusion codifier détester nuancer phrase amateur héron boulon sorcier novateur décrire agacer impact", 77 | "passphrase": "TREZOR", 78 | "seed": "be84f96be871eaa09b5b6d36f94342489e821ceef6d551a4aad4d9357e9c4b96a778d8518fb8c382a8cd7d1cbc43bceba76f5f9a835aa3fc5bea734cfd2de9ab", 79 | "bip32_xprv": "xprv9s21ZrQH143K2jWgzyME2ofnF6PV7Q1P7tFiAGri4MrJB7bdpK236L5fhU4NLxnKoqBJTB9uRuxPggvXJ4gHVfudYku5QzNN44be5uzChKU" 80 | }, 81 | { 82 | "entropy": "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", 83 | "mnemonic": "censurer cheval tuteur superbe toxine cavalier usure gazon nouveau farouche passion puceron meuble fuite urticant crier totem stimulus hachoir dénuder palourde pavoiser littoral social", 84 | "passphrase": "TREZOR", 85 | "seed": "e0686d5de43478652af2ad67d963decd26ef96022cd2088079af4f7adc5dbaf2f8cb992d3c1d0f28f9a883cd5affc558c6d3f2cc879bbf55bf6db4829718d335", 86 | "bip32_xprv": "xprv9s21ZrQH143K33hdXzRWQZyizEaPucvtHa4RJBjh4KUTvGow13mAaYa8zBGYcbZwk4vYLAUwMEHfjmTdCqFcwqmn99sZMmVMWoEwws5m3hz" 87 | }, 88 | { 89 | "entropy": "eaebabb2383351fd31d703840b32e9e2", 90 | "mnemonic": "thorax étrange tonique gélatine cohésion vortex rasage sottise intrigue éruption pixel querelle", 91 | "passphrase": "TREZOR", 92 | "seed": "62f8a4471a712f888dca0b676ed2a7d14e2e9edf490b41d7c9830e18f10359c5c83b656c0b196f992ec695ef51d35782147b5478eec6f525352876f02add2e01", 93 | "bip32_xprv": "xprv9s21ZrQH143K4DsRfkTdxQjJsk9KqZMhs94RthUAJEcAR5B24qMqLjuijdbD4gKB69364hRzqtD548taBzJdB2wSy6LGZzY3gPcaBzKVMe5" 94 | }, 95 | { 96 | "entropy": "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", 97 | "mnemonic": "homard brèche déchirer toxine chemise comédie tragique aliment pluie fortune vaillant concert étirer maximal maussade frémir odorant protéger", 98 | "passphrase": "TREZOR", 99 | "seed": "6511cdc7011b62f0d518d15de676a1c5c1c1d4e08e17209157ff6be6f87cce330addc35b247ca99dbabb68edf7f1c8f8de26aad25c2a1af6be655c639ae5c5d7", 100 | "bip32_xprv": "xprv9s21ZrQH143K4DR3RNnBvhB4vC7tZJzNduNmypMFEyuoxDYjd3MY1VZ63upGeFtZDzwJbqxBxLfoehZbwpA5LSpEx16kAwdsJv8Tjqrj5vE" 101 | }, 102 | { 103 | "entropy": "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", 104 | "mnemonic": "élaborer anéantir chenille humble scinder guerrier écharpe prélude anonyme cinéma adresse bronzer cimenter dorure inviter garnir public mondial ralentir arriver aveugle féroce virtuose suricate", 105 | "passphrase": "TREZOR", 106 | "seed": "31aab1fcfa23db8976ebe42738b1e3dca2b2f1f75bc7d0fa810e739422c2286935c1037be1172e27682702678ac4e76ca3552c8ce0597a4a00e2f8d3f72a6594", 107 | "bip32_xprv": "xprv9s21ZrQH143K3NWzNDsNxmvcdSKZRcX2asXnkpkGuSzGU6UBtDsw9oJXYXs4rNH9yUo6hBMH6fiDJCGJUP8LJKXcBrX4CoftMitFiBuMX8R" 108 | }, 109 | { 110 | "entropy": "18ab19a9f54a9274f03e5209a2ac8a91", 111 | "mnemonic": "baleine épuisant forcer thème obtenir créditer présence région algue augurer brave brochure", 112 | "passphrase": "TREZOR", 113 | "seed": "f283aad985086927dbdd7e948d29c014dfcc1e4de9cb7f6b140a0d23f24e7386ae978ffe9dcfcfe7215fd9874d89646425fa1765d80edfc3a92cfb96ff504f3b", 114 | "bip32_xprv": "xprv9s21ZrQH143K3tXUyufRCWxJVXfi3UPXxqgGkdMYaH3JocQ1R1uJKwBhzXhqi4SfriQdZES9j6D7D1yRURWuuUnKpFDCdvceNFpQ948iJE2" 115 | }, 116 | { 117 | "entropy": "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", 118 | "mnemonic": "baleine aviser grogner connoter torche séduire légume griffure relatif expédier tendre gorille peser ficeler gouffre plateau loyal calvaire", 119 | "passphrase": "TREZOR", 120 | "seed": "a5d07758ddd70074dcdc39c6166eea091f7eb10b646708540bdd3cfd617944ddbc4844b8fc2af1e92af3504b0dfe20a92eb68eeef0f4f71cd8e0f793848ba882", 121 | "bip32_xprv": "xprv9s21ZrQH143K4CpMDJk4LwtnvEr6oRsXccYE1MGWymLykwF6fYnZwvHuAbzn5uHVTrhgozCqU7DKY8oHnaY76GqjoQHx9y7TkD9SgmyJPCs" 122 | }, 123 | { 124 | "entropy": "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", 125 | "mnemonic": "autruche rythme relever causer astuce tiroir sucre imiter anodin astre exposer essieu blessant réactif fidèle tolérant lavoir amiral médecin mortier cobra superbe arbitre cérébral", 126 | "passphrase": "TREZOR", 127 | "seed": "3e9a3b483d0f9773a392318b12140dc84796c5391736f29ddb45b033f2cb4e1ea8b81c7192c4ca49fe7da0e5c39441a33f036f0d233896d76644133ea0068369", 128 | "bip32_xprv": "xprv9s21ZrQH143K2kHYTt8X36uZkDhwKaQeBwuTNvXexvrBV13yFVf9u7d3k31kvCbP2QoDamx3ZDXn6DW1oHUc9BRf7MMjLXz5xgjpvnBew2h" 129 | } 130 | ] 131 | } -------------------------------------------------------------------------------- /src/test/resources/bip39_japanese_test_vectors.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": "https://github.com/bip32JP/bip32JP.github.io/blob/master/test_JP_BIP39.json", 3 | "data": [ 4 | { 5 | "entropy": "00000000000000000000000000000000", 6 | "mnemonic": "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", 7 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 8 | "seed": "a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55", 9 | "bip32_xprv": "xprv9s21ZrQH143K258jAiWPAM6JYT9hLA91MV3AZUKfxmLZJCjCHeSjBvMbDy8C1mJ2FL5ytExyS97FAe6pQ6SD5Jt9SwHaLorA8i5Eojokfo1" 10 | }, 11 | { 12 | "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 13 | "mnemonic": "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかめ", 14 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 15 | "seed": "aee025cbe6ca256862f889e48110a6a382365142f7d16f2b9545285b3af64e542143a577e9c144e101a6bdca18f8d97ec3366ebf5b088b1c1af9bc31346e60d9", 16 | "bip32_xprv": "xprv9s21ZrQH143K3ra1D6uGQyST9UqtUscH99GK8MBh5RrgPkrQo83QG4o6H2YktwSKvoZRVXDQZQrSyCDpHdA2j8i3PW5M9LkauaaTKwym1Wf" 17 | }, 18 | { 19 | "entropy": "80808080808080808080808080808080", 20 | "mnemonic": "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あかちゃん", 21 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 22 | "seed": "e51736736ebdf77eda23fa17e31475fa1d9509c78f1deb6b4aacfbd760a7e2ad769c714352c95143b5c1241985bcb407df36d64e75dd5a2b78ca5d2ba82a3544", 23 | "bip32_xprv": "xprv9s21ZrQH143K2aDKfG8hpfvRXzANmyBQWoqoUXWaSwVZcKtnmX5xTVkkHAdD9yykuuBcagjCFK6iLcBdHHxXC1g3TT9xHSu4PW6SRf3KvVy" 24 | }, 25 | { 26 | "entropy": "ffffffffffffffffffffffffffffffff", 27 | "mnemonic": "われる われる われる われる われる われる われる われる われる われる われる ろんぶん", 28 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 29 | "seed": "4cd2ef49b479af5e1efbbd1e0bdc117f6a29b1010211df4f78e2ed40082865793e57949236c43b9fe591ec70e5bb4298b8b71dc4b267bb96ed4ed282c8f7761c", 30 | "bip32_xprv": "xprv9s21ZrQH143K4WxYzpW3izjoq6e51NSZgN6AHxoKxZStsxBvtxuQDxPyvb8o4pSbxYPCyJGKewMxrHWvTBY6WEFX4svSzB2ezmatzzJW9wi" 31 | }, 32 | { 33 | "entropy": "000000000000000000000000000000000000000000000000", 34 | "mnemonic": "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あらいぐま", 35 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 36 | "seed": "d99e8f1ce2d4288d30b9c815ae981edd923c01aa4ffdc5dee1ab5fe0d4a3e13966023324d119105aff266dac32e5cd11431eeca23bbd7202ff423f30d6776d69", 37 | "bip32_xprv": "xprv9s21ZrQH143K2pqcK1QdBVm9r4gL4yQX6KFTqHWctvfZa9Wjhxow63ZGpSB27mVo1BBH4D1NoTo3gVAHAeqmhm5Z9SuC8xJmFYBFz978rza" 38 | }, 39 | { 40 | "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 41 | "mnemonic": "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れいぎ", 42 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 43 | "seed": "eaaf171efa5de4838c758a93d6c86d2677d4ccda4a064a7136344e975f91fe61340ec8a615464b461d67baaf12b62ab5e742f944c7bd4ab6c341fbafba435716", 44 | "bip32_xprv": "xprv9s21ZrQH143K34NWKwHe5cBVDYuoKZ6iiqWczDMwGA9Ut57iCCTksDTnxE5AH3qHHvfcgwpRhyj4G7Y6FEewjVoQqq4gHN6CetyFdd3q4CR" 45 | }, 46 | { 47 | "entropy": "808080808080808080808080808080808080808080808080", 48 | "mnemonic": "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら いきなり", 49 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 50 | "seed": "aec0f8d3167a10683374c222e6e632f2940c0826587ea0a73ac5d0493b6a632590179a6538287641a9fc9df8e6f24e01bf1be548e1f74fd7407ccd72ecebe425", 51 | "bip32_xprv": "xprv9s21ZrQH143K4RABcYmYKbZybgJrvpcnricsuNaZvsGVo7pupfELFY6TJw5G5XVswQodBzaRtfPkTi6aVCmC349A3yYzAZLfT7emP8m1RFX" 52 | }, 53 | { 54 | "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffff", 55 | "mnemonic": "われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる りんご", 56 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 57 | "seed": "f0f738128a65b8d1854d68de50ed97ac1831fc3a978c569e415bbcb431a6a671d4377e3b56abd518daa861676c4da75a19ccb41e00c37d086941e471a4374b95", 58 | "bip32_xprv": "xprv9s21ZrQH143K2ThaKxBDxUByy4gNwULJyqKQzZXyF3aLyGdknnP18KvKVZwCvBJGXaAsKd7oh2ypLbjyDn4bDY1iiSPvNkKsVAGQGj7G3PZ" 59 | }, 60 | { 61 | "entropy": "0000000000000000000000000000000000000000000000000000000000000000", 62 | "mnemonic": "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん いってい", 63 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 64 | "seed": "23f500eec4a563bf90cfda87b3e590b211b959985c555d17e88f46f7183590cd5793458b094a4dccc8f05807ec7bd2d19ce269e20568936a751f6f1ec7c14ddd", 65 | "bip32_xprv": "xprv9s21ZrQH143K3skSyXVw9CTTUHgKnsysvKiJw9MQjvTSY6ysTk4sFz58htMAcqHrjLdnUhqxRtmRy5AMJyWGeuQrDGSSfmcNh7cbfnrbDty" 66 | }, 67 | { 68 | "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 69 | "mnemonic": "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん まんきつ", 70 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 71 | "seed": "cd354a40aa2e241e8f306b3b752781b70dfd1c69190e510bc1297a9c5738e833bcdc179e81707d57263fb7564466f73d30bf979725ff783fb3eb4baa86560b05", 72 | "bip32_xprv": "xprv9s21ZrQH143K2y9p1D6KuxqypMjbiBKkiALERahpxvb46x9giqkvmv5KxGvGJZG2mdcMunmHaazYyEqYmkx9SnfndimSmgJv5EL24X1DGqV" 73 | }, 74 | { 75 | "entropy": "8080808080808080808080808080808080808080808080808080808080808080", 76 | "mnemonic": "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる うめる", 77 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 78 | "seed": "6b7cd1b2cdfeeef8615077cadd6a0625f417f287652991c80206dbd82db17bf317d5c50a80bd9edd836b39daa1b6973359944c46d3fcc0129198dc7dc5cd0e68", 79 | "bip32_xprv": "xprv9s21ZrQH143K2TuQM4HcbBBtvC19SaDgqn6cL16KTaPEazB26iCDfxABvBi9driWcbnF4rcLVpkx5iGG7zH2QcN7qNxL4cpb7mQ2G3ByAv7" 80 | }, 81 | { 82 | "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 83 | "mnemonic": "われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる らいう", 84 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 85 | "seed": "a44ba7054ac2f9226929d56505a51e13acdaa8a9097923ca07ea465c4c7e294c038f3f4e7e4b373726ba0057191aced6e48ac8d183f3a11569c426f0de414623", 86 | "bip32_xprv": "xprv9s21ZrQH143K3XTGpC53cWswvhg6GVQ1dE1yty6F9VhBcE7rnXmStuKwtaZNXRxw5N7tsh1REyAxun1S5BCYvhD5pNwxWUMMZaHwjTmXFdb" 87 | }, 88 | { 89 | "entropy": "77c2b00716cec7213839159e404db50d", 90 | "mnemonic": "せまい うちがわ あずき かろう めずらしい だんち ますく おさめる ていぼう あたる すあな えしゃく", 91 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 92 | "seed": "344cef9efc37d0cb36d89def03d09144dd51167923487eec42c487f7428908546fa31a3c26b7391a2b3afe7db81b9f8c5007336b58e269ea0bd10749a87e0193", 93 | "bip32_xprv": "xprv9s21ZrQH143K2fhvZfecKw8znj6QkGGV2F2t17BWA6VnanejVWBjQeV5DspseWdSvN49rrFpocPGt7aSGk9R5wJfC1LAwFMt6hV9qS7yGKR" 94 | }, 95 | { 96 | "entropy": "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", 97 | "mnemonic": "ぬすむ ふっかつ うどん こうりつ しつじ りょうり おたがい せもたれ あつめる いちりゅう はんしゃ ごますり そんけい たいちょう らしんばん ぶんせき やすみ ほいく", 98 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 99 | "seed": "b14e7d35904cb8569af0d6a016cee7066335a21c1c67891b01b83033cadb3e8a034a726e3909139ecd8b2eb9e9b05245684558f329b38480e262c1d6bc20ecc4", 100 | "bip32_xprv": "xprv9s21ZrQH143K25BDHG8fiLEPvKD9QCWqqs8V4yz2NeZXHbDgnAYW1EL5k8KWcn1kGKmsHrqbNvePJaYWEgkEMjJEepwTFfVzzyYRN7cyJgM" 101 | }, 102 | { 103 | "entropy": "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", 104 | "mnemonic": "くのう てぬぐい そんかい すろっと ちきゅう ほあん とさか はくしゅ ひびく みえる そざい てんすう たんぴん くしょう すいようび みけん きさらぎ げざん ふくざつ あつかう はやい くろう おやゆび こすう", 105 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 106 | "seed": "32e78dce2aff5db25aa7a4a32b493b5d10b4089923f3320c8b287a77e512455443298351beb3f7eb2390c4662a2e566eec5217e1a37467af43b46668d515e41b", 107 | "bip32_xprv": "xprv9s21ZrQH143K2gbMb94GNwdogai6fA3vTrALH8eoNJKqPWn9KyeBMhUQLpsN5ePJkZdHsPmyDsECNLRaYiposqDDqsbk3ANk9hbsSgmVq7G" 108 | }, 109 | { 110 | "entropy": "0460ef47585604c5660618db2e6a7e7f", 111 | "mnemonic": "あみもの いきおい ふいうち にげる ざんしょ じかん ついか はたん ほあん すんぽう てちがい わかめ", 112 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 113 | "seed": "0acf902cd391e30f3f5cb0605d72a4c849342f62bd6a360298c7013d714d7e58ddf9c7fdf141d0949f17a2c9c37ced1d8cb2edabab97c4199b142c829850154b", 114 | "bip32_xprv": "xprv9s21ZrQH143K2Ec1okKMST9mN52SKEybSCeacWpAvPHMS5zFfMDfgwpJVXa96sd2sybGuJWE34CtSVYn42FBWLmFgmGeEmRvDriPnZVjWnU" 115 | }, 116 | { 117 | "entropy": "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", 118 | "mnemonic": "すろっと にくしみ なやむ たとえる へいこう すくう きない けってい とくべつ ねっしん いたみ せんせい おくりがな まかい とくい けあな いきおい そそぐ", 119 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 120 | "seed": "9869e220bec09b6f0c0011f46e1f9032b269f096344028f5006a6e69ea5b0b8afabbb6944a23e11ebd021f182dd056d96e4e3657df241ca40babda532d364f73", 121 | "bip32_xprv": "xprv9s21ZrQH143K2KKucNRqjGFooHw87xXFQpZGNZ1W7Vwtkr2YMkXFuxnMvqc8cegm8jkrVswEWuNEsGtFkaEedAG2cRTTtsz1bM6o8fCu3Pg" 122 | }, 123 | { 124 | "entropy": "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", 125 | "mnemonic": "かほご きうい ゆたか みすえる もらう がっこう よそう ずっと ときどき したうけ にんか はっこう つみき すうじつ よけい くげん もくてき まわり せめる げざい にげる にんたい たんそく ほそく", 126 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 127 | "seed": "713b7e70c9fbc18c831bfd1f03302422822c3727a93a5efb9659bec6ad8d6f2c1b5c8ed8b0b77775feaf606e9d1cc0a84ac416a85514ad59f5541ff5e0382481", 128 | "bip32_xprv": "xprv9s21ZrQH143K2MXrVTP5hyWW9js9D8qipo9vVRTKYPCB8Mtw4XE57uepG7wuHRk3ZJLGAq1tdJ4So8hYHu4gBaJ4NANPjb1CJCpDd3e9H87" 129 | }, 130 | { 131 | "entropy": "eaebabb2383351fd31d703840b32e9e2", 132 | "mnemonic": "めいえん さのう めだつ すてる きぬごし ろんぱ はんこ まける たいおう さかいし ねんいり はぶらし", 133 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 134 | "seed": "06e1d5289a97bcc95cb4a6360719131a786aba057d8efd603a547bd254261c2a97fcd3e8a4e766d5416437e956b388336d36c7ad2dba4ee6796f0249b10ee961", 135 | "bip32_xprv": "xprv9s21ZrQH143K3ZVFWWSR9XVXY8EMqCNdj7YUx4DKdcCFitEsSH18aPcufobUfP3w9xz1XTUThwC4cYuf8VWvSwYWs8aTTAi7mr9jDsGHYLU" 136 | }, 137 | { 138 | "entropy": "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", 139 | "mnemonic": "せんぱい おしえる ぐんかん もらう きあい きぼう やおや いせえび のいず じゅしん よゆう きみつ さといも ちんもく ちわわ しんせいじ とめる はちみつ", 140 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 141 | "seed": "1fef28785d08cbf41d7a20a3a6891043395779ed74503a5652760ee8c24dfe60972105ee71d5168071a35ab7b5bd2f8831f75488078a90f0926c8e9171b2bc4a", 142 | "bip32_xprv": "xprv9s21ZrQH143K3CXbNxjnq5iemN7AzZrtE71rvBAuZ4BnebovyS2hK3yjbAzsX6mrdxK8fa4kXPjnCC9FHpwgaPwZuCbrUJ4sj6xdPPYNeKK" 143 | }, 144 | { 145 | "entropy": "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", 146 | "mnemonic": "こころ いどう きあつ そうがんきょう へいあん せつりつ ごうせい はいち いびき きこく あんい おちつく きこえる けんとう たいこ すすめる はっけん ていど はんおん いんさつ うなぎ しねま れいぼう みつかる", 147 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 148 | "seed": "43de99b502e152d4c198542624511db3007c8f8f126a30818e856b2d8a20400d29e7a7e3fdd21f909e23be5e3c8d9aee3a739b0b65041ff0b8637276703f65c2", 149 | "bip32_xprv": "xprv9s21ZrQH143K2WyZ5cAUSqkC89FeL4mrEG9N9VEhh9pR2g6SQjWbXNufkfBwwaZtMfpDzip9fZjm3huvMEJASWviaGqG1A6bDmoSQzd3YFy" 150 | }, 151 | { 152 | "entropy": "18ab19a9f54a9274f03e5209a2ac8a91", 153 | "mnemonic": "うりきれ さいせい じゆう むろん とどける ぐうたら はいれつ ひけつ いずれ うちあわせ おさめる おたく", 154 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 155 | "seed": "3d711f075ee44d8b535bb4561ad76d7d5350ea0b1f5d2eac054e869ff7963cdce9581097a477d697a2a9433a0c6884bea10a2193647677977c9820dd0921cbde", 156 | "bip32_xprv": "xprv9s21ZrQH143K49xMPBpnqsaXt6EECMPzVAvr18EiiJMHfgEedw28JiSCpB5DLGQB19NU2iiG4g7vVnLC6jn75B4n3LHCPwhpU6o7Srd6jYt" 157 | }, 158 | { 159 | "entropy": "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", 160 | "mnemonic": "うりきれ うねる せっさたくま きもち めんきょ へいたく たまご ぜっく びじゅつかん さんそ むせる せいじ ねくたい しはらい せおう ねんど たんまつ がいけん", 161 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 162 | "seed": "753ec9e333e616e9471482b4b70a18d413241f1e335c65cd7996f32b66cf95546612c51dcf12ead6f805f9ee3d965846b894ae99b24204954be80810d292fcdd", 163 | "bip32_xprv": "xprv9s21ZrQH143K2WyY1Me9W7T8Wg7yQa9WFVAEn1vhoDkkP43dBVhsagabzEKMaz7UNtczbKkNowDLXSyVipJXVEBcpYJGBJ6ZaVDXNGoLStz" 164 | }, 165 | { 166 | "entropy": "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", 167 | "mnemonic": "うちゅう ふそく ひしょ がちょう うけもつ めいそう みかん そざい いばる うけとる さんま さこつ おうさま ぱんつ しひょう めした たはつ いちぶ つうじょう てさぎょう きつね みすえる いりぐち かめれおん", 168 | "passphrase": "㍍ガバヴァぱばぐゞちぢ十人十色", 169 | "seed": "346b7321d8c04f6f37b49fdf062a2fddc8e1bf8f1d33171b65074531ec546d1d3469974beccb1a09263440fc92e1042580a557fdce314e27ee4eabb25fa5e5fe", 170 | "bip32_xprv": "xprv9s21ZrQH143K2qVq43Phs1xyVc6jSxXHWJ6CDJjod3cgyEin7hgeQV6Dkw6s1LSfMYxoah4bPAnW4wmXfDUS9ghBEM18xoY634CBtX8HPrA" 171 | } 172 | ] 173 | } -------------------------------------------------------------------------------- /src/test/resources/bip39_spanish_test_vectors.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": "https://iancoleman.github.io/bip39/#french", 3 | "data": [ 4 | { 5 | "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 6 | "mnemonic": "ligero vista talar yogur venta queso yacer trozo ligero vista talar zafiro", 7 | "passphrase": "TREZOR", 8 | "seed": "1580aa5d5d67057b3a0a12253c283b93921851555529d0bbe9634349d641029216f791ddce3527819d44d833a0df3500b15fd8ba4cae7ca24e1464b9167de633", 9 | "bip32_xprv": "xprv9s21ZrQH143K27g7EMkgY2F1fuyqSEKq6n1iJCHuiUX5F3oGESmJSS6DcKW5JZ6qWWJ7x8wS1FCrd1NhRS4xCWDn9Bb1HzBuNpitD7FeYGv" 10 | }, 11 | { 12 | "entropy": "ffffffffffffffffffffffffffffffff", 13 | "mnemonic": "zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo yodo", 14 | "passphrase": "TREZOR", 15 | "seed": "a9d1f751178872cc53fc5433e9b2a97526448adc4b824cedeadd8a127c2416481345dfbef2bfc78275f3498e40b4e8e2e00560100e543aba3f324e752f032bc9", 16 | "bip32_xprv": "xprv9s21ZrQH143K4TU3oETVCyPLTqmC8C7zqqSR7L8JpMiR68YNhyvfEmXpRh6pP8gPghpFbvNSQCQppPDf55iNnZhT9iza6HRpTvKeLSDNFCg" 17 | }, 18 | { 19 | "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 20 | "mnemonic": "ligero vista talar yogur venta queso yacer trozo ligero vista talar yogur venta queso yacer trozo ligero violín", 21 | "passphrase": "TREZOR", 22 | "seed": "f73b28d7e180e0a92c57276a29489c10a992c8a465ab61be0ade4708543436a682b2a3c22de57c48736ae6f29bebf3e506779c74bc1a835ad6b9f4e174126ca8", 23 | "bip32_xprv": "xprv9s21ZrQH143K4PEMCi1dMq3ZwveC5um6cXR3tp4Z6LUGLhz4pmkaDU44UoSTiMQHv5icYPjH5EooZNorbDB7fLMDa531HHrKKnEEqCT5Tfs" 24 | }, 25 | { 26 | "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffff", 27 | "mnemonic": "zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo viejo", 28 | "passphrase": "TREZOR", 29 | "seed": "2fd3964ac77c52232dc0eb2ab237fea2de9b7509005214101ecbbaeb40f34bce7735e848fca6339f76f289904c6db959fa573fc0aa607d969ac256693b4fb7af", 30 | "bip32_xprv": "xprv9s21ZrQH143K3zwjASrAazc9EGeoVcQXA3unTmgxG9ZS7nc75inZw19oktj1y3n2Y7yetBatSN3v2UpS9ms3PvmrgQEMC4jox4ZV1ZrW6Qz" 31 | }, 32 | { 33 | "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 34 | "mnemonic": "ligero vista talar yogur venta queso yacer trozo ligero vista talar yogur venta queso yacer trozo ligero vista talar yogur venta queso yacer teatro", 35 | "passphrase": "TREZOR", 36 | "seed": "3d2a3aec779195f2628e800879d600cfaf2d7fcfa998657068db53906a00608fcc94fc78ceab8c97d6191389c4e468815ea0d11ffa4280c34c3cf17721a27c73", 37 | "bip32_xprv": "xprv9s21ZrQH143K2WBRPum95TFxfz8niK5sbiDpQjyr915SjEJc99BrYoRhPuYvfzFhPwqUNAFtEdw4khqQMK4ge8EnTZZASbv7oy8t6SMzVSM" 38 | }, 39 | { 40 | "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 41 | "mnemonic": "zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo varón", 42 | "passphrase": "TREZOR", 43 | "seed": "deea21c6902df5ef4a8efab8e14de53004c68817ea3de421cdd184f4159a6e9947376ed794c3ce67534f37f80b46674e85335555b5c53f44fdfef27991fedc0e", 44 | "bip32_xprv": "xprv9s21ZrQH143K4TyBobPSoDLEze5gKjiTZXzaJaND1QHqmrnx6kULMJhGvQkraSHgUsjmisepryPQqTfWyM3ETLjusTsW35KumQ3w3RyusSM" 45 | }, 46 | { 47 | "entropy": "77c2b00716cec7213839159e404db50d", 48 | "mnemonic": "jungla asumir acción cedro tóxico mismo tapa brisa obispo ácido hombre baño", 49 | "passphrase": "TREZOR", 50 | "seed": "338e1ee586e109e80a53af2294bca03f4a5a7e9d089f04d1f02b30dde370c8ae4268a37909bd278c21e29fc24e2a3f30104eb8dd153192eda5646415dbc21fc0", 51 | "bip32_xprv": "xprv9s21ZrQH143K2x4M1WPDA2xUXubnVRGrrNrVvFasrcQBF2hVJVbhK8bT9BgugRsj5Pn6tiggNtUoxM7uFvTobSLmCavLfbedssaKZQxKqMU" 52 | }, 53 | { 54 | "entropy": "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", 55 | "mnemonic": "pleito semana ático ensayo giro viaje buceo júpiter activo amigo repetir fábula llover madera veinte siete trompa soplar", 56 | "passphrase": "TREZOR", 57 | "seed": "12e9454bfe0cb26cb91db194f7be1297ea0f0ff07038f9f70fc3364a85f4196991b01c7ec84ebc91f0611597c8b346cd20e2623ce8c0af8e4040cf7bc05f2218", 58 | "bip32_xprv": "xprv9s21ZrQH143K2PzJFum2Ei6JvNjYzj535XbrbTCbsbpbVWq5Vh78iZN2cWkYqqBaUtbkX8uiXbtdpzdRpJujb2TKuW7EP8KKWRmx1NBaaeE" 59 | }, 60 | { 61 | "entropy": "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", 62 | "mnemonic": "cúpula odiar llorar inicio moreno sopa ozono rápido rotar tejer libro opción moho cubrir horno tema cigarro diadema sardina acné relato dátil cacao espejo", 63 | "passphrase": "TREZOR", 64 | "seed": "acb2b4e604937ce8bbd1048577fc9cc4f864551d28772f572068b6749ddbd38a9afcb189a62453ceae15542cc1af7e9e5372e62d113a6db88d5250ab6afce4f1", 65 | "bip32_xprv": "xprv9s21ZrQH143K4PTThgM38jX2WphKQQx8QK6w3HvZ6dcrFGHwn3pUqpH4ELpEDevUZN7Jnd9ujEyWLuZeniohRsLGQzTdBjrQaEL8oUsaQhB" 66 | }, 67 | { 68 | "entropy": "0460ef47585604c5660618db2e6a7e7f", 69 | "mnemonic": "aduana ajuste samba perder gafas gen natal rebote sopa innato ochenta zafiro", 70 | "passphrase": "TREZOR", 71 | "seed": "fbeec9484d0ba972601190f2201049c522c1b24b8a3584478f2ca11dd58683c232241df21dca593f0beb1c9842323f81c9fd53d19d9af1be7686424c746711b6", 72 | "bip32_xprv": "xprv9s21ZrQH143K2za5f2wdZoSm6ywEdgfNuTWFkg95ULZnzb5MXdnnP1uiJcXQJNec9rdgx1g7gQMAxdb1yf1haoU3F5tXGTJa4XmbwbGpoT7" 73 | }, 74 | { 75 | "entropy": "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", 76 | "mnemonic": "inicio pera pelar medio simio hueso cocina directo óvulo pompa amante lágrima bóveda talento ostra defensa ajuste lienzo", 77 | "passphrase": "TREZOR", 78 | "seed": "26ec835839a0556796cb2f483ea6965cfa845a059867df950a8314d0d7edca4eacb1076e4aa7977d321ae90da1a29893c2025e2f585d4839637fefed3abc1f26", 79 | "bip32_xprv": "xprv9s21ZrQH143K3a26sVzhsQKqLwrEATUBs6mJFzPdaXeHnijK5EdmCBGmZATF8mwS5vz2PMXbQ83e39Ynj1EE7yusoS8ySbkdSiP3v2b6gG5" 80 | }, 81 | { 82 | "entropy": "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", 83 | "mnemonic": "castor cetro úlcera tender tren carne vaina icono oso geranio piloto red nivel hoyo vacío croqueta trazar tauro juntar día perder piojo miseria sur", 84 | "passphrase": "TREZOR", 85 | "seed": "e030c576214c756d847e79429be634d2054cb489f37f01d892a7393cc368927bd6af4203c96aa34e237fcb96365b7d4ed02e20c518818a12944efde5fc6e6ea4", 86 | "bip32_xprv": "xprv9s21ZrQH143K2jx39oUuMtyGwWuzAjpbto1Bdp7PKYpuk98XkhhtbFZVZfPvBYyJktNT3xPCmccD9uJ6TJEryHpVtFa2hmj2WeAhuMyVXv3" 87 | }, 88 | { 89 | "entropy": "eaebabb2383351fd31d703840b32e9e2", 90 | "mnemonic": "tórax fracaso trabajo idioma codo yeso reparto tamaño lucha fila prensa rehén", 91 | "passphrase": "TREZOR", 92 | "seed": "a5083e544700dc9933be40a727afdd373a4e417b4ec97b1382c2758836320a8b3d16d06a4d649d8173544867bb59cd89528024a14aac0a40dc6026502bd96020", 93 | "bip32_xprv": "xprv9s21ZrQH143K4ZKxR9pRMZ1kySME5N9QQp3hXX6Fu4C7xbAJH5y5xNmMLEn9PUJjxD2hsMHa4bjUcJuBCwWpD7pKKTnQnyLKcfgUfftFRED" 94 | }, 95 | { 96 | "entropy": "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", 97 | "mnemonic": "langosta broma débil tren cero colgar tribu almíbar prole hebra vampiro colmo forro nasal nariz historia pañuelo recaer", 98 | "passphrase": "TREZOR", 99 | "seed": "be98fe494599826bd0056d02596eccee914ead5b8bd6387920663e813d3965ae1d9f0ca0c2eba3f888a2ddd41736cb2dc25ea5ee625e09b69e067edc2a0729fb", 100 | "bip32_xprv": "xprv9s21ZrQH143K34DKqaMXeDBNpVyjXY8hG6Ze2y9dU84LqahdmsiNQrfcnG84Ss993d9dJ5abZxhyDS2ciiUDQkqYGGvBjSQCERkcNfCUswM" 101 | }, 102 | { 103 | "entropy": "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", 104 | "mnemonic": "esfera ángulo cerrar leer sílaba juez encargo ración anuncio cielo agrio buey ciego educar lunes hundir recurso número remo área atleta gorila visor tenso", 105 | "passphrase": "TREZOR", 106 | "seed": "337858f949a2f0fe56c0d9995c768af0237036751e2b7b09e9c60a6f5263e2499319f5702b3bdeb19e7a424f2ebe42d2f3746faf26520ae7a2173d623b4a2581", 107 | "bip32_xprv": "xprv9s21ZrQH143K3GqJJ1jGQ1g6fZTEgbM45NMrCFVWZvuEtCtX1AdhkZGSHVPEUxZ6R2xJDycABK2xozbfG9yMSacuPWCyfER3Uhyusxe4bEU" 108 | }, 109 | { 110 | "entropy": "18ab19a9f54a9274f03e5209a2ac8a91", 111 | "mnemonic": "avena fiel haz topar palco crimen raíz rigor alma astuto brisa bucle", 112 | "passphrase": "TREZOR", 113 | "seed": "805b75dfa5021feb4212af6508364acb71bc26f3ae3e1b04d46997da276ffb3698b55986d20eaf26d60d8ab4a57fbebb6caed0d63cd68e5f2ce523880e5082df", 114 | "bip32_xprv": "xprv9s21ZrQH143K2JH1XgjetHqEKTTtt9hukDL9SUjTAvBX9zTacuBXbKEkei4d7DvCPvFnYYNgSpW2RT149GGY9mfN4xs1y1jWxTJb6yNHdej" 115 | }, 116 | { 117 | "entropy": "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", 118 | "mnemonic": "avena atún jeringa comida tráfico sobre mente jaula ritmo gala tobillo íntimo poesía grano inútil probar molde calle", 119 | "passphrase": "TREZOR", 120 | "seed": "82509727ea09696854191b68976f202411fcf6cfa26187bbf5bf3fe966f12fe2d13629ed71eafed0624db2a5b2214b80b3394c910d87801b7f6844b29c9e901d", 121 | "bip32_xprv": "xprv9s21ZrQH143K3k2YsodupKc1CJWmnwpt1HQTs2KtExtsTT2zdCfoLsGfRpPAdP3n2LFk8i5QXWQwFmJ4gL3LnbaWwDumArstGmsf82j4BiM" 122 | }, 123 | { 124 | "entropy": "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", 125 | "mnemonic": "atajo secta rito carga asalto torpedo teléfono libro anual asado gallo flauta boa rescate gratis toser melón ameno náusea obvio clínica tender apuro caudal", 126 | "passphrase": "TREZOR", 127 | "seed": "9f99ae125b87b67703d85562f90a95c2f72066a3bc39e7b4578c7f79856949f3fd4acf976743b9be9cac0e2e1063e7bc86ca8ddffcc2b67efcc8b31d69adc067", 128 | "bip32_xprv": "xprv9s21ZrQH143K3sr5hCfTBtsRJ2cWY6fQ1RqkwSXCrfURJfZFMVWtF2Ljfhy3nixFknUPYwDHtUQwks6LD2hvQ48k6Ze5cWgm39ocAaEw5Tu" 129 | } 130 | ] 131 | } --------------------------------------------------------------------------------