Skip to content

Commit

Permalink
More key management enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Dec 4, 2024
1 parent 1f62ab9 commit 3228f0f
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 24 deletions.
9 changes: 8 additions & 1 deletion convex-cli/src/main/java/convex/cli/key/KeyGenerate.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import convex.cli.ExitCodes;
import convex.core.crypto.AKeyPair;
import convex.core.crypto.BIP39;
import convex.core.crypto.SLIP10;
import convex.core.data.ABlob;
import convex.core.data.Blob;
import convex.core.data.Blobs;
Expand Down Expand Up @@ -47,6 +48,12 @@ public class KeyGenerate extends AKeyCommand {
description="Type of key generation. Supports random, bip39, entropy")
private String type;

@Option(names={"--path"},
defaultValue=convex.core.Constants.DEFAULT_BIP39_PATH,
description="Derivation path for SLIP-0010 when using BIP39. Default: ${DEFAULT-VALUE}")
private String path;


@Option(names="--passphrase",
description="BIP39 passphrase. If not provided, will be requested from user (or assumed blank in non-interactive mode).")
private String passphrase;
Expand Down Expand Up @@ -78,7 +85,7 @@ private AKeyPair generateKeyPair() {
paranoia("Cannot use an empty BIP39 passphrase for key generation with strict security");
}
Blob bipseed = BIP39.getSeed(mnemonic, passphrase);
AKeyPair result= BIP39.seedToKeyPair(bipseed);
AKeyPair result=SLIP10.deriveKeyPair(bipseed, path);
return result;
} else if ("random".equals(type)) {
return AKeyPair.generate();
Expand Down
5 changes: 5 additions & 0 deletions convex-core/src/main/java/convex/core/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,5 +179,10 @@ public class Constants {
*/
public static final int CHAIN_CODE = 864;

/**
* Default derivation path for Convex keys
*/
public static final String DEFAULT_BIP39_PATH = "m/44/"+CHAIN_CODE+"/0/0/0";


}
21 changes: 21 additions & 0 deletions convex-core/src/main/java/convex/core/crypto/BIP39.java
Original file line number Diff line number Diff line change
Expand Up @@ -515,5 +515,26 @@ public static String checkWords(List<String> words) {
public static String extendWord(String abbr) {
return ABBR.get(abbr.trim().toLowerCase());
}

public static int[] parsePath(String path) {
try {
String[] es=path.split("/");
if (!"m".equals(es[0])) throw new Exception("<Bad derivation path, must start with 'm'>");

int n=es.length-1;
int[] proposedPath=new int[n];
for (int i=0; i<n; i++) {
try {
Integer ix= Integer.parseInt(es[i+1]);
proposedPath[i]=ix;
} catch (NumberFormatException e) {
throw new Exception("<Bad derivation path, should be integer indexes 'm/44/888/1/0/123' >");
}
}
return proposedPath;
} catch (Exception ex) {
return null;
}
}

}
5 changes: 5 additions & 0 deletions convex-core/src/main/java/convex/core/crypto/SLIP10.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,10 @@ public static AKeyPair deriveKeyPair(Blob bip39seed, int... ixs) {
return kp;
}

public static AKeyPair deriveKeyPair(Blob bip39seed, String path) {
return deriveKeyPair(bip39seed,BIP39.parsePath(path));
}



}
22 changes: 22 additions & 0 deletions convex-core/src/test/java/convex/core/crypto/BIP39Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,28 @@ public void doMnemonicTest(String m) {
assertEquals(newGen,BIP39.normaliseFormat(newGen));
}

@Test
public void testDerivePath() {
// Ed25199 Test vector 2 from : https://github.com/satoshilabs/slips/blob/master/slip-0010.md
Blob seed = Blob.fromHex("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542");
{
Blob priv=SLIP10.deriveKeyPair(seed, "m").getSeed();
assertEquals(priv,SLIP10.deriveKeyPair(seed, new int[0]).getSeed());
assertEquals("171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012",priv.toHexString());
}

{
Blob priv=SLIP10.deriveKeyPair(seed, "m/0").getSeed();
assertEquals("1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635",priv.toHexString());
}

{
Blob priv=SLIP10.deriveKeyPair(seed, "m/0/2147483647/1/2147483646/2").getSeed();
assertEquals("551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d",priv.toHexString());
}


}

@Test
public void testValidStrings() {
Expand Down
25 changes: 2 additions & 23 deletions convex-gui/src/main/java/convex/gui/keys/KeyGenPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ private String checkWarnings(String s, String p) {
private void updatePath() {
try {
String path=derivationArea.getText();
this.derivationPath=parsePath(path);
this.derivationPath=BIP39.parsePath(path);
deriveSeed();
} catch (Exception ex) {
privateKeyArea.setText(ex.getMessage());
Expand All @@ -168,27 +168,6 @@ private void updatePath() {
}
}

private static int[] parsePath(String path) {
try {
String[] es=path.split("/");
if (!"m".equals(es[0])) throw new Exception("<Bad derivation path, must start with 'm'>");

int n=es.length-1;
int[] proposedPath=new int[n];
for (int i=0; i<n; i++) {
try {
Integer ix= Integer.parseInt(es[i+1]);
proposedPath[i]=ix;
} catch (NumberFormatException e) {
throw new Exception("<Bad derivation path, should be integer indexes 'm/44/888/1/0/123' >");
}
}
return proposedPath;
} catch (Exception ex) {
return null;
}
}

private void updateSeed() {
mnemonicArea.setText("<can't recreate from BIP39 seed>");
deriveSeed();
Expand All @@ -202,7 +181,7 @@ private void deriveSeed() {
Blob mb=SLIP10.getMaster(b);
masterKeyArea.setText(mb.toHexString());
Blob db;
this.derivationPath=parsePath(derivationArea.getText());
this.derivationPath=BIP39.parsePath(derivationArea.getText());
if (derivationPath==null) {
db=mb;
} else {
Expand Down

0 comments on commit 3228f0f

Please sign in to comment.