Added bip39 and brainkey seeds

This commit is contained in:
henry 2018-01-06 23:21:46 -04:00
parent bef004048a
commit 7b027d4e79
6 changed files with 236 additions and 7 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,48 @@
# Note that these are the currency symbols to use for the specified code when displaying in a DIFFERENT locale than
# the home locale of the currency. This file can be edited as needed. In addition, if in some case one specific locale
# would use a symbol DIFFERENT than the standard international one listed here, then an additional properties file
# can be added making use of the standard ResourceBundle loading algorithm. For example, if we decided we wanted to
# show US dollars as just $ instead of US$ when in the UK, we could create a file i18nCurrencySymbols_en_GB.properties
# with the entry USD=$
ARS=$AR
AUD=AU$
BOB=$b
BRL=R$
CAD=CAN$
CLP=Ch$
COP=COL$
CRC=\u20A1
HRK=kn
CZK=K\u010D
DOP=RD$
XCD=EC$
EUR=\u20AC
GTQ=Q
GYD=G$
HNL=L
HKD=HK$
HUF=Ft
INR=\u20B9
IDR=Rp
ILS=\u20AA
JMD=J$
JPY=JP\u00A5
KRW=\u20A9
NZD=NZ$
NIO=C$
PAB=B/.
PYG=Gs
PEN=S/.
PHP=\u20B1
PLN=\u007A\u0142
RON=lei
SGD=S$
ZAR=R
TWD=NT$
THB=\u0E3F
TTD=TT$
GBP=\u00A3
USD=$
UYU=$U
VEF=Bs
VND=\u20AB

View file

@ -1,13 +1,26 @@
package cy.agorise.crystalwallet.models; package cy.agorise.crystalwallet.models;
import android.accounts.Account;
import android.arch.persistence.room.ColumnInfo; import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity; import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey; import android.arch.persistence.room.PrimaryKey;
import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.recyclerview.extensions.DiffCallback; import android.support.v7.recyclerview.extensions.DiffCallback;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.crypto.HDKeyDerivation;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import cy.agorise.crystalwallet.enums.SeedType; import cy.agorise.crystalwallet.enums.SeedType;
import cy.agorise.crystalwallet.models.seed.BIP39;
import cy.agorise.graphenej.BrainKey;
import static cy.agorise.crystalwallet.enums.SeedType.BRAINKEY;
/** /**
* Represents a type of crypto seed for HD wallets * Represents a type of crypto seed for HD wallets
@ -97,4 +110,46 @@ public class AccountSeed {
return mMasterSeed.equals(that.mMasterSeed); return mMasterSeed.equals(that.mMasterSeed);
} }
public static AccountSeed getAccountSeed(SeedType type, Context context){
BufferedReader reader = null;
switch (type) {
case BRAINKEY:
try {
reader = new BufferedReader(new InputStreamReader(context.getAssets().open("brainkeydict.txt"), "UTF-8"));
String dictionary = reader.readLine();
String brainKeySuggestion = BrainKey.suggest(dictionary);
AccountSeed seed = new AccountSeed();
seed.setMasterSeed(brainKeySuggestion);
seed.setType(BRAINKEY);
return seed;
} catch (IOException e) {
e.printStackTrace();
}
case BIP39:
try {
reader = new BufferedReader(new InputStreamReader(context.getAssets().open("bip39dict.txt"), "UTF-8"));
String dictionary = reader.readLine();
//TODO save in db
return new BIP39(dictionary.split(","));
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public ECKey getPrivateKey(){
switch (this.type) {
case BRAINKEY:
return new BrainKey(this.mMasterSeed,0).getPrivateKey();
case BIP39:
return HDKeyDerivation.createMasterPrivateKey(new BIP39(mId, mMasterSeed).getSeed());
}
return null;
}
} }

View file

@ -3,6 +3,9 @@ package cy.agorise.crystalwallet.models;
import android.content.Context; import android.content.Context;
import org.bitcoinj.core.ECKey; import org.bitcoinj.core.ECKey;
import org.bitcoinj.crypto.ChildNumber;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDKeyDerivation;
import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.enums.SeedType; import cy.agorise.crystalwallet.enums.SeedType;
@ -55,10 +58,20 @@ public class GrapheneAccount extends CryptoNetAccount {
if(seed == null) if(seed == null)
return null; return null;
if(seed.getType().equals(SeedType.BRAINKEY)){ if(seed.getType().equals(SeedType.BRAINKEY)){
return new BrainKey(seed.getMasterSeed(),0).getPrivateKey(); return seed.getPrivateKey();
}else{ }else{
//TODO implement slip48 DeterministicKey masterKey = (DeterministicKey) seed.getPrivateKey();
return null; DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey(masterKey,
new ChildNumber(48, true));
DeterministicKey networkKey = HDKeyDerivation.deriveChildKey(purposeKey,
new ChildNumber(1, true));
DeterministicKey accountIndexKey = HDKeyDerivation.deriveChildKey(networkKey,
new ChildNumber(0, true));
DeterministicKey permission = HDKeyDerivation.deriveChildKey(accountIndexKey,
new ChildNumber(0, true));
DeterministicKey address = HDKeyDerivation.deriveChildKey(permission,
new ChildNumber(0, true));
return address;
} }
} }
@ -72,8 +85,17 @@ public class GrapheneAccount extends CryptoNetAccount {
if(seed.getType().equals(SeedType.BRAINKEY)){ if(seed.getType().equals(SeedType.BRAINKEY)){
return new BrainKey(seed.getMasterSeed(),0).getPrivateKey(); return new BrainKey(seed.getMasterSeed(),0).getPrivateKey();
}else{ }else{
//TODO implement slip48 DeterministicKey masterKey = (DeterministicKey) seed.getPrivateKey();
return null; DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey(masterKey,
new ChildNumber(48, true));
DeterministicKey networkKey = HDKeyDerivation.deriveChildKey(purposeKey,
new ChildNumber(1, true));
DeterministicKey accountIndexKey = HDKeyDerivation.deriveChildKey(networkKey,
new ChildNumber(0, true));
DeterministicKey permission = HDKeyDerivation.deriveChildKey(accountIndexKey,
new ChildNumber(1, true));
return HDKeyDerivation.deriveChildKey(permission,
new ChildNumber(0, true)); //TODO implement multiple Address and accounts
} }
} }
@ -87,8 +109,17 @@ public class GrapheneAccount extends CryptoNetAccount {
if(seed.getType().equals(SeedType.BRAINKEY)){ if(seed.getType().equals(SeedType.BRAINKEY)){
return new BrainKey(seed.getMasterSeed(),0).getPrivateKey(); return new BrainKey(seed.getMasterSeed(),0).getPrivateKey();
}else{ }else{
//TODO implement slip48 DeterministicKey masterKey = (DeterministicKey) seed.getPrivateKey();
return null; DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey(masterKey,
new ChildNumber(48, true));
DeterministicKey networkKey = HDKeyDerivation.deriveChildKey(purposeKey,
new ChildNumber(1, true));
DeterministicKey accountIndexKey = HDKeyDerivation.deriveChildKey(networkKey,
new ChildNumber(0, true));
DeterministicKey permission = HDKeyDerivation.deriveChildKey(accountIndexKey,
new ChildNumber(3, true));
return HDKeyDerivation.deriveChildKey(permission,
new ChildNumber(0, true)); //TODO implement multiple Address and accounts
} }
} }
} }

View file

@ -0,0 +1,93 @@
package cy.agorise.crystalwallet.models.seed;
import org.bitcoinj.crypto.MnemonicCode;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import cy.agorise.crystalwallet.enums.SeedType;
import cy.agorise.crystalwallet.models.AccountSeed;
import cy.agorise.graphenej.crypto.SecureRandomGenerator;
/**
* Created by henry on 6/1/2018.
*/
public class BIP39 extends AccountSeed{
/**
* Teh amount of words for this seed
*/
private final int wmWordNumber = 12;
/**
* Constructor from the dataabse
* @param id The id on the database of this seed
*/
public BIP39(long id, String words) {
this.setId(id);
this.setType(SeedType.BIP39);
this.setMasterSeed(words);
}
/**
* Constructor that generates the list of words
* @param wordList Dictionary to be used
*/
public BIP39(String[] wordList) {
try {
this.setType(SeedType.BIP39);
int entropySize = ((this.wmWordNumber * 11) / 8) * 8;
// We get a true random number
SecureRandom secureRandom = SecureRandomGenerator.getSecureRandom();
byte[] entropy = new byte[entropySize / 8];
secureRandom.nextBytes(entropy);
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] shaResult = md.digest(entropy);
int mask = 0x80;
int cheksum = 0;
for (int i = 0; i < entropySize / 32; i++) {
cheksum = cheksum ^ (shaResult[0] & mask);
mask = mask / 2;
}
int[] wordsIndex = new int[(entropySize / 11) + 1];
for (int i = 0; i < wordsIndex.length; i++) {
wordsIndex[i] = 0;
}
int lastIndex = 0;
int lastBit = 0;
for (int i = 0; i < entropy.length; i++) {
for (int j = 7; j >= 0; j--) {
if (lastBit == 11) {
lastBit = 0;
++lastIndex;
}
wordsIndex[lastIndex] = wordsIndex[lastIndex] ^ ((int) (Math.pow(2, 11 - (lastBit + 1))) * (entropy[i] & ((int) Math.pow(2, j))) >> j);
++lastBit;
}
}
for (int j = 7; j >= 0; j--) {
if (lastBit == 11) {
break;
}
wordsIndex[lastIndex] = wordsIndex[lastIndex] ^ ((int) (Math.pow(2, 11 - (lastBit + 1))) * (cheksum & ((int) Math.pow(2, j))) >> j);
++lastBit;
}
StringBuilder words = new StringBuilder();
for (int windex : wordsIndex) {
words.append(wordList[windex]).append(" ");
}
words.deleteCharAt(words.length() - 1);
this.setMasterSeed(words.toString());
} catch (NoSuchAlgorithmException ex) {
}
}
public byte[] getSeed() {
return MnemonicCode.toSeed(Arrays.asList(this.getMasterSeed().split(" ")), "");
}
}