diff --git a/convex-core/src/main/java/convex/core/crypto/BIP39.java b/convex-core/src/main/java/convex/core/crypto/BIP39.java index 0dffa8240..1b737b60a 100644 --- a/convex-core/src/main/java/convex/core/crypto/BIP39.java +++ b/convex-core/src/main/java/convex/core/crypto/BIP39.java @@ -210,6 +210,9 @@ public class BIP39 { public static final int BITS_PER_WORD=11; + public static final String DEMO_PHRASE="sing bomb stay manual powder hard north mixture sausage lunch retreat desert"; + public static final String DEMO_PASS="hello1234567890ZZ"; + /** * Map of words to integer values */ @@ -244,14 +247,7 @@ public class BIP39 { * @return Blob containing BIP39 seed (64 bytes) */ public static Blob getSeed(List words, String passphrase) throws NoSuchAlgorithmException, InvalidKeySpecException { - if (passphrase==null) passphrase=""; - - // Normalise words and convert to char array - String joined=Utils.joinStrings(words, " "); - joined=Normalizer.normalize(joined, Normalizer.Form.NFKD); - char[] pass= joined.toCharArray(); - - return getSeedInternal(pass,passphrase); + return getSeed(mnemonic(words),passphrase); } public static AKeyPair seedToKeyPair(Blob seed) { @@ -365,7 +361,7 @@ public static List createWords(byte[] entropy, int n) { } /** - * Gets the individual words from a mnemonic String. Will trim and normalise whitespace, convert to lowercase + * Gets the individual words from a mnemonic String. Will trim and normalise whitespace * @param mnemonic Mnemonic String * @return List of words */ @@ -376,9 +372,7 @@ public static List getWords(String mnemonic) { ArrayList al=new ArrayList<>(); for (int i=0; i words=getWords(s); + + int n=words.size(); + for (int i=0; i words) { @@ -417,5 +434,14 @@ public static String checkWords(List words) { } return null; } + + /** + * Extends an abbreviated form of a BIP39 word to a full word e.g. 'SHAL' => 'shallow' + * @param abbr + * @return + */ + public static String extendWord(String abbr) { + return ABBR.get(abbr.trim().toLowerCase()); + } } diff --git a/convex-core/src/test/java/convex/core/crypto/BIP39Test.java b/convex-core/src/test/java/convex/core/crypto/BIP39Test.java index e1f441c65..51f8f9e81 100644 --- a/convex-core/src/test/java/convex/core/crypto/BIP39Test.java +++ b/convex-core/src/test/java/convex/core/crypto/BIP39Test.java @@ -47,6 +47,14 @@ public void testFromEntropy() { } + @Test + public void testExtendWord() { + assertEquals("shallow",BIP39.extendWord("SHAL")); + assertEquals("zoo",BIP39.extendWord(" zoo ")); + assertEquals("list",BIP39.extendWord("list")); + assertEquals("capital",BIP39.extendWord("capi")); + } + @Test public void testSeed() throws NoSuchAlgorithmException, InvalidKeySpecException { List tw1=List.of("blue claw trip feature street glue element derive dentist rose daring cash".split(" ")); diff --git a/convex-gui/src/main/java/convex/gui/keys/KeyGenPanel.java b/convex-gui/src/main/java/convex/gui/keys/KeyGenPanel.java index 18a521056..ef05d6b17 100644 --- a/convex-gui/src/main/java/convex/gui/keys/KeyGenPanel.java +++ b/convex-gui/src/main/java/convex/gui/keys/KeyGenPanel.java @@ -87,10 +87,42 @@ private void updatePass() { private void generateBIP39Seed() { String s = mnemonicArea.getText(); String p = new String(passArea.getPassword()); + List words=BIP39.getWords(s); + + String warn=checkWarnings(s,p); + + if (warn.isBlank()) { + warningArea.setForeground(Color.GREEN); + warningArea.setText("OK: Reasonable mnemonic and passphrase"); + } else { + warningArea.setForeground(Color.ORANGE); + warningArea.setText("WARNING: "+warn); + } + + try { + Blob bipSeed=BIP39.getSeed(words,p); + seedArea.setText(bipSeed.toHexString()); + deriveSeed(); + } catch (Exception ex) { + String pks = ""; + if (s.isBlank()) pks = ""; + masterKeyArea.setText(pks); + warningArea.setText(""); + derivedKeyArea.setText(pks); + privateKeyArea.setText(pks); + } + } + + private String checkWarnings(String s, String p) { + String warn =""; + + // Check for demo phrases + if (s.equals(BIP39.DEMO_PHRASE)) warn+= "Demo mnemonic (for testing only). "; + if (p.equals(BIP39.DEMO_PASS)) warn+= "Demo passphrase (for testing only). "; + List words=BIP39.getWords(s); String badWord=BIP39.checkWords(words); - String warn=""; int numWords=words.size(); if (numWords { String s=mnemonicArea.getText(); - String s2=BIP39.normaliseFormat(s); + String s2=BIP39.normaliseAll(s); mnemonicArea.setText(s2); updateMnemonic(); });