Skip to content

Commit

Permalink
0.16.0 printing generated valid seeds
Browse files Browse the repository at this point in the history
  • Loading branch information
PawelGorny committed Jan 20, 2022
1 parent 6886104 commit 3126c27
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 8 deletions.
9 changes: 9 additions & 0 deletions examples/example_26.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
PRINT_SEEDS
anyText
6
brother
canal
?
remove
pitch
hill
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.pawelgorny</groupId>
<artifactId>lostword</artifactId>
<version>0.15.0</version>
<version>0.16.0</version>
<packaging>jar</packaging>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/pawelgorny/lostword/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private void parseScript(String targetAddress) {
this.coin = Configuration.ETHEREUM;
}
}
if (!WORK.ONE_UNKNOWN_CHECK_ALL.equals(work) && !WORK.PERMUTATION.equals(work)){
if (!WORK.ONE_UNKNOWN_CHECK_ALL.equals(work) && !WORK.PERMUTATION.equals(work) && !WORK.PRINT_SEEDS.equals(work)){
if (this.ethereumAddress==null){
switch (getDBscriptType()){
case P2PKH:
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/pawelgorny/lostword/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private static Configuration readConfiguration(String file) {
}
words.add(line);
}
}else if (WORK.KNOWN_POSITION.equals(work) || WORK.PERMUTATION.equals(work) || WORK.PERMUTATION_CHECK.equals(work)){
}else if (WORK.KNOWN_POSITION.equals(work) || WORK.PERMUTATION.equals(work) || WORK.PERMUTATION_CHECK.equals(work)|| WORK.PRINT_SEEDS.equals(work)){
if (words.size() == size) {
path = line;
}else if (words.size() < size) {
Expand Down Expand Up @@ -153,7 +153,7 @@ private static Configuration readConfiguration(String file) {
if (WORK.POOL.equals(work)){
configuration.setWORDS_POOL(wordsPool);
}
if (WORK.KNOWN_POSITION.equals(work) && words.get(size-1).equalsIgnoreCase("?")){
if ((WORK.KNOWN_POSITION.equals(work)||WORK.PRINT_SEEDS.equals(work)) && words.get(size-1).equalsIgnoreCase("?")){
for (int s=9, b=3; s<=24; s+=3, b++){
if (s==size){
configuration.setMissingChecksum(true);
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/pawelgorny/lostword/WORK.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.pawelgorny.lostword;

public enum WORK {
ONE_UNKNOWN, KNOWN_POSITION, ONE_UNKNOWN_CHECK_ALL, POOL, PERMUTATION, PERMUTATION_CHECK
ONE_UNKNOWN, KNOWN_POSITION, ONE_UNKNOWN_CHECK_ALL, POOL, PERMUTATION, PERMUTATION_CHECK,
PRINT_SEEDS
}
22 changes: 21 additions & 1 deletion src/main/java/com/pawelgorny/lostword/Worker.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public class Worker {
private final int CONCAT_LEN_BITS_MINUS_CONCAT_LEN_BITS_DIV_33;
private final int CONCAT_LEN_BITS_MINUS_CONCAT_LEN_BITS_DIV_33__DIV8;

protected final List<String> PRINT_SEEDS=new ArrayList<>(0);

public Worker(Configuration configuration) {
this.configuration = configuration;
this.CONCAT_LEN_BITS = 11 * configuration.getSIZE();
Expand Down Expand Up @@ -84,9 +86,12 @@ public void run() throws InterruptedException, MnemonicException {
case PERMUTATION:
worker = new WorkerPermutation(configuration);
break;
case PRINT_SEEDS:
worker = new WorkerPrintSeeds(configuration);
break;
}
System.out.println("--- Starting worker --- "+ SDTF.format(new Date())+" ---");
if (WORK.PERMUTATION.equals(configuration.getWork())){
if (WORK.PERMUTATION.equals(configuration.getWork()) || WORK.PRINT_SEEDS.equals(configuration.getWork())){
worker.run();
System.out.println();
return;
Expand Down Expand Up @@ -173,6 +178,21 @@ protected Boolean check(final List<String> mnemonic, HMac SHA512DIGEST, MessageD
return false;
}

protected Boolean checkPrint(final List<String> mnemonic, HMac SHA512DIGEST, MessageDigest sha256) throws MnemonicException {
if (!checksumCheck(mnemonic, sha256)){
return configuration.isMissingChecksum()?null:false;
}

if (Configuration.ETHEREUM.equals(configuration.getCoin())){
return checkEthereum(mnemonic);
}

String seed = Utils.SPACE_JOINER.join(mnemonic);
System.out.println(seed);
PRINT_SEEDS.add(seed);
return true;
}

protected boolean checkEthereum(final List<String> mnemonic) throws MnemonicException {
DeterministicSeed seed = new DeterministicSeed(mnemonic, null, "", System.currentTimeMillis());
DeterministicKeyChain chain = DeterministicKeyChain.builder().seed(seed).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class WorkerKnownPosition extends Worker{

private static int NUMBER_UNKNOWN;
private long start = 0;
private long COUNTER = 0L;

public WorkerKnownPosition(Configuration configuration) {
super(configuration);
Expand Down Expand Up @@ -109,13 +110,15 @@ private void checkUnknown(int position) throws InterruptedException {
private Boolean processSeed(final List<String> seed, int depth, int positionStartSearch, boolean reporter, HMac SHA_512_DIGEST, MessageDigest SHA_256_DIGEST) throws MnemonicException {
if (NUMBER_UNKNOWN==depth){
Boolean checkResult = check(seed, SHA_512_DIGEST, SHA_256_DIGEST);
COUNTER++;
if (checkResult!=null&&checkResult){
System.out.println(seed);
RESULT = new Result(new ArrayList<>(seed));
return true;
}
if (reporter && (System.currentTimeMillis()-start > STATUS_PERIOD)){
System.out.println(SDTF.format(new Date())+ " Alive!");
System.out.println(SDTF.format(new Date())+ " Alive! "+(COUNTER));
COUNTER = 0;
start = System.currentTimeMillis();
}
return configuration.isMissingChecksum()?(checkResult==null?false:null):checkResult;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class WorkerPermutationCheck extends Worker{

private MessageDigest SHA_256_DIGEST;
private long start = 0;
long counter = 0L;

public WorkerPermutationCheck(Configuration configuration) {
super(configuration);
Expand Down Expand Up @@ -114,14 +115,18 @@ private boolean checkElements(String[] target, String[] input, HMac LOCAL_SHA_51
List<String> mnemonic = Arrays.asList(target);
try {
boolean result = check(mnemonic, LOCAL_SHA_512_DIGEST, LOCAL_SHA_256_DIGEST);
if (REPORTER) {
counter++;
}
if (result){
RESULT = new Result(mnemonic);
}
}catch (MnemonicException e){
System.out.println(e.getLocalizedMessage());
}
if (REPORTER && (System.currentTimeMillis()-start > STATUS_PERIOD)){
System.out.println(SDTF.format(new Date())+ " Alive!");
System.out.println(SDTF.format(new Date())+ " Alive! "+counter);
counter = 0;
start = System.currentTimeMillis();
}
return (RESULT!=null);
Expand Down
205 changes: 205 additions & 0 deletions src/main/java/com/pawelgorny/lostword/WorkerPrintSeeds.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package com.pawelgorny.lostword;

import org.bitcoinj.crypto.MnemonicException;
import org.bouncycastle.crypto.macs.HMac;

import java.io.FileWriter;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class WorkerPrintSeeds extends Worker{

private static int NUMBER_UNKNOWN;
private long start = 0;
private long COUNTER = 0L;

public WorkerPrintSeeds(Configuration configuration) {
super(configuration);
THREADS = 1;
}

public void run() throws InterruptedException, MnemonicException {
check();
try {
FileWriter fileWriter = new FileWriter(this.configuration.getWork().name() + "_result_" + SDTCF.format(new Date()) + ".txt", false);
for (String seed:PRINT_SEEDS) {
fileWriter.write(seed+"\r\n");
}
fileWriter.close();
} catch (IOException e) {
System.out.println("Cannot write to file: " + e.getLocalizedMessage());
}
}

private void check() throws MnemonicException, InterruptedException {
NUMBER_UNKNOWN = 0;
int position = -1;
int c=0;
for (String word : configuration.getWORDS()){
if (Configuration.UNKNOWN_CHAR.equalsIgnoreCase(word)){
NUMBER_UNKNOWN++;
if (position==-1) {
position = c;
}
}
c++;
}
if (NUMBER_UNKNOWN == 1){
checkOne(position);
}
else{
checkUnknown(position);
}
}

private int getNextUnknown(int startSearch, List<String> list){
for (int p0=startSearch; p0<list.size(); p0++){
if (Configuration.UNKNOWN_CHAR.equals(list.get(p0))){
return p0;
}
}
return -1;
}

private void checkUnknown(int position) throws InterruptedException {
System.out.println("Warning: "+((Double)Math.pow(DICTIONARY_SIZE, NUMBER_UNKNOWN)).longValue()+" possibilities!");
List<String> mnemonic = new ArrayList<>(configuration.getWORDS());
List<List<String>> DICTIONARY = split();
int nextPosition = getNextUnknown(1+position, configuration.getWORDS());

final List<MessageDigest> SHA_256_DIGESTS= new ArrayList<>(THREADS);
final List<HMac> SHA_512_DIGESTS= new ArrayList<>(THREADS);
for (int t=0; t<THREADS; t++){
try {
SHA_512_DIGESTS.add(createHmacSha512Digest());
SHA_256_DIGESTS.add(MessageDigest.getInstance("SHA-256"));
}catch (Exception e){
}
}

for (int w0=configuration.getKnownStart(); RESULT==null && w0<DICTIONARY_SIZE; w0++){
String processedWord = Configuration.MNEMONIC_CODE.getWordList().get(w0);
System.out.println("Processing word "+(w0+1)+"/"+DICTIONARY_SIZE+" on position "+(position+1)+"! '"+processedWord+"' "+ SDTF.format(new Date()));
mnemonic.set(position, processedWord);
final CountDownLatch latch = new CountDownLatch(THREADS);
final ExecutorService executorService = Executors.newFixedThreadPool(THREADS);
for (int t = 0; t < THREADS; t++) {
final int WORKING_POSITION = nextPosition;
final List<String> SEED = new LinkedList<>(mnemonic);
final List<String> WORDS_TO_WORK = DICTIONARY.get(t);
final boolean REPORTER = t==0;
final int T_NUMBER=t;
executorService.submit(() -> {
if (REPORTER) {
start = System.currentTimeMillis();
}
final HMac LOCAL_SHA_512_DIGEST = SHA_512_DIGESTS.get(T_NUMBER);
final MessageDigest LOCAL_SHA_256_DIGEST = SHA_256_DIGESTS.get(T_NUMBER);
try {
int WORKING_POSITION_PLUS = WORKING_POSITION+1;
for (int bipPosition = 0; RESULT == null && bipPosition < WORDS_TO_WORK.size(); bipPosition++) {
SEED.set(WORKING_POSITION, WORDS_TO_WORK.get(bipPosition));
processSeed(SEED, 2, WORKING_POSITION_PLUS, REPORTER, LOCAL_SHA_512_DIGEST, LOCAL_SHA_256_DIGEST);
}
} catch (Exception e) {
Thread.currentThread().interrupt();
}
latch.countDown();
});
}
latch.await();
executorService.shutdown();
}
}

private Boolean processSeed(final List<String> seed, int depth, int positionStartSearch, boolean reporter, HMac SHA_512_DIGEST, MessageDigest SHA_256_DIGEST) throws MnemonicException {
if (NUMBER_UNKNOWN==depth){
Boolean checkResult = checkPrint(seed, SHA_512_DIGEST, SHA_256_DIGEST);
COUNTER++;
if (checkResult!=null&&checkResult){
System.out.println(seed);
RESULT = new Result(new ArrayList<>(seed));
return true;
}
if (reporter && (System.currentTimeMillis()-start > STATUS_PERIOD)){
System.out.println(SDTF.format(new Date())+ " Alive! "+(COUNTER));
COUNTER = 0;
start = System.currentTimeMillis();
}
return configuration.isMissingChecksum()?(checkResult==null?false:null):checkResult;
}else{
int nextDepth = depth + 1;
int position = getNextUnknown(positionStartSearch, seed);
if(position == -1){
Boolean checkResult = check(seed, SHA_512_DIGEST, SHA_256_DIGEST);
if (checkResult!=null&&checkResult){
System.out.println(seed);
RESULT = new Result(new ArrayList<>(seed));
}
return false;
}
int positionStartNextSearch = 0;
if (nextDepth <NUMBER_UNKNOWN ){
positionStartNextSearch = position+1;
}
int checksumCheckLimit = configuration.getMissingChecksumLimit();
for (int w = 0; RESULT==null && w<DICTIONARY_SIZE; w++){
seed.set(position, Configuration.MNEMONIC_CODE.getWordList().get(w));
Boolean result = processSeed(seed, nextDepth, positionStartNextSearch, reporter, SHA_512_DIGEST, SHA_256_DIGEST);
if(result == null && --checksumCheckLimit==0){
break;
}
}
seed.set(position, Configuration.UNKNOWN_CHAR);
}
return false;
}

private void checkOne(int position) throws InterruptedException {
List<List<String>> DICTIONARY = split();
System.out.println("Checking missing word at position " + (position + 1));
Iterator<String> iterator = configuration.getWORDS().iterator();
int p = 0;
List<String> mnemonic = new ArrayList<>(configuration.getSIZE());
for (int i = 0; i < configuration.getSIZE(); i++) {
mnemonic.add("");
}
while (iterator.hasNext()) {
String word = iterator.next();
if (Configuration.UNKNOWN_CHAR.equalsIgnoreCase(word)){
continue;
}
if (p == position) {
p++;
}
mnemonic.set(p++, word);
}
final CountDownLatch latch = new CountDownLatch(THREADS);
final ExecutorService executorService = Executors.newFixedThreadPool(THREADS);
for (int t = 0; t < THREADS; t++) {
final int WORKING_POSITION = position;
final List<String> WORDS_TO_WORK = DICTIONARY.get(t);
final List<String> SEED = new ArrayList<>(mnemonic);
executorService.submit(() -> {
try {
final MessageDigest LOCAL_SHA_256_DIGEST = MessageDigest.getInstance("SHA-256");
final HMac LOCAL_SHA_512_DIGEST = createHmacSha512Digest();
for (int bipPosition = 0; RESULT == null && bipPosition < WORDS_TO_WORK.size(); bipPosition++) {
SEED.set(WORKING_POSITION, WORDS_TO_WORK.get(bipPosition));
checkPrint(SEED, LOCAL_SHA_512_DIGEST, LOCAL_SHA_256_DIGEST);
}
} catch (Exception e) {
Thread.currentThread().interrupt();
}
latch.countDown();
});
}
latch.await();
executorService.shutdown();
}

}

0 comments on commit 3126c27

Please sign in to comment.