Added bip39 and brainkey seeds
parent
bef004048a
commit
7b027d4e79
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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
|
|
@ -1,13 +1,26 @@
|
|||
package cy.agorise.crystalwallet.models;
|
||||
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.arch.persistence.room.ColumnInfo;
|
||||
import android.arch.persistence.room.Entity;
|
||||
import android.arch.persistence.room.PrimaryKey;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
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.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
|
||||
|
@ -97,4 +110,46 @@ public class AccountSeed {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@ package cy.agorise.crystalwallet.models;
|
|||
import android.content.Context;
|
||||
|
||||
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.enums.SeedType;
|
||||
|
@ -55,10 +58,20 @@ public class GrapheneAccount extends CryptoNetAccount {
|
|||
if(seed == null)
|
||||
return null;
|
||||
if(seed.getType().equals(SeedType.BRAINKEY)){
|
||||
return new BrainKey(seed.getMasterSeed(),0).getPrivateKey();
|
||||
return seed.getPrivateKey();
|
||||
}else{
|
||||
//TODO implement slip48
|
||||
return null;
|
||||
DeterministicKey masterKey = (DeterministicKey) seed.getPrivateKey();
|
||||
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)){
|
||||
return new BrainKey(seed.getMasterSeed(),0).getPrivateKey();
|
||||
}else{
|
||||
//TODO implement slip48
|
||||
return null;
|
||||
DeterministicKey masterKey = (DeterministicKey) seed.getPrivateKey();
|
||||
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)){
|
||||
return new BrainKey(seed.getMasterSeed(),0).getPrivateKey();
|
||||
}else{
|
||||
//TODO implement slip48
|
||||
return null;
|
||||
DeterministicKey masterKey = (DeterministicKey) seed.getPrivateKey();
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(" ")), "");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue