Merge branch 'master' of https://github.com/Agorise/crystal-wallet-android
This commit is contained in:
commit
cf5aa56d32
6 changed files with 236 additions and 7 deletions
1
app/src/main/assets/bip39dict.txt
Normal file
1
app/src/main/assets/bip39dict.txt
Normal file
File diff suppressed because one or more lines are too long
1
app/src/main/assets/brainkeydict.txt
Normal file
1
app/src/main/assets/brainkeydict.txt
Normal file
File diff suppressed because one or more lines are too long
48
app/src/main/assets/correctedI18nCurrencySymbols.properties
Normal file
48
app/src/main/assets/correctedI18nCurrencySymbols.properties
Normal 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
|
|
@ -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 a new issue