diff --git a/core/src/main/java/com/google/bitcoin/crypto/HDUtils.java b/core/src/main/java/com/google/bitcoin/crypto/HDUtils.java index 4cf991b6..dd42e3a1 100644 --- a/core/src/main/java/com/google/bitcoin/crypto/HDUtils.java +++ b/core/src/main/java/com/google/bitcoin/crypto/HDUtils.java @@ -1,5 +1,6 @@ /** * Copyright 2013 Matija Mazi. + * Copyright 2014 Giannis Dzegoutanis. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,11 +25,15 @@ import org.spongycastle.crypto.digests.SHA512Digest; import org.spongycastle.crypto.macs.HMac; import org.spongycastle.crypto.params.KeyParameter; +import javax.annotation.Nonnull; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Static utilities used in BIP 32 Hierarchical Deterministic Wallets (HDW). */ @@ -71,4 +76,27 @@ public final class HDUtils { public static String formatPath(List path) { return PATH_JOINER.join(Iterables.concat(Collections.singleton("M"), path)); } + + /** + * The path is a human-friendly representation of the deterministic path. For example: + * + * "44' / 0' / 0' / 1 / 1" + * + * Where a single quote (') means hardened key. Spaces are ignored. + */ + public static List parsePath(@Nonnull String path) { + String[] parsedNodes = path.split("/"); + List nodes = new ArrayList(); + + for (String n : parsedNodes) { + n = n.replaceAll(" ", ""); + if (n.length() == 0) continue; + boolean isHard = n.endsWith("'"); + if (isHard) n = n.substring(0, n.length() - 1); + int nodeNumber = Integer.parseInt(n); + nodes.add(new ChildNumber(nodeNumber, isHard)); + } + + return nodes; + } } diff --git a/core/src/test/java/com/google/bitcoin/crypto/HDUtilsTest.java b/core/src/test/java/com/google/bitcoin/crypto/HDUtilsTest.java index ef7e86d1..91a50ee9 100644 --- a/core/src/test/java/com/google/bitcoin/crypto/HDUtilsTest.java +++ b/core/src/test/java/com/google/bitcoin/crypto/HDUtilsTest.java @@ -17,14 +17,13 @@ package com.google.bitcoin.crypto; +import com.google.common.collect.ImmutableList; import org.junit.Assert; import org.junit.Test; import static com.google.bitcoin.core.Utils.HEX; +import java.util.List; -/** - * @author Matija Mazi
- */ public class HDUtilsTest { @Test public void testHmac() throws Exception { @@ -124,4 +123,29 @@ public class HDUtilsTest { byte[] bytes = HDUtils.longTo4ByteArray(1026); Assert.assertEquals("00000402", HEX.encode(bytes)); } + + @Test + public void testParsePath() { + Object tv[] = { + "44' / 0' / 0' / 1 / 1", + ImmutableList.of(new ChildNumber(44, true), new ChildNumber(0, true), new ChildNumber(0, true), + new ChildNumber(1, false), new ChildNumber(1, false)), + + "/7'/3/3/1'/", + ImmutableList.of(new ChildNumber(7, true), new ChildNumber(3, false), new ChildNumber(3, false), + new ChildNumber(1, true)), + + "1 ' / 2 ' / 3 ' /", + ImmutableList.of(new ChildNumber(1, true), new ChildNumber(2, true), new ChildNumber(3, true)), + + "1 ' / 2 ' / 3 ' /", + ImmutableList.of(new ChildNumber(1, true), new ChildNumber(2, true), new ChildNumber(3, true)) + }; + + for (int i = 0; i < tv.length; i += 2) { + List path = HDUtils.parsePath((String) tv[i]); + + Assert.assertEquals(path, tv[i+1]); + } + } }