3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-07 14:54:15 +00:00

Rename ExtendedHierarchicKey to DeterministicKey. Add annotations and rewrite a bit of code to satisfy static analysis.

This commit is contained in:
Mike Hearn 2013-07-11 13:41:46 +02:00
parent 50dd5af0c8
commit 000d81d54f
7 changed files with 82 additions and 68 deletions

View File

@ -23,6 +23,7 @@ package com.google.bitcoin.crypto.hd;
*/
public class ChildNumber {
public static final int PRIV_BIT = 0x80000000;
public static final ChildNumber ZERO = new ChildNumber(0);
/** Integer i as per BIP 32 spec, including the MSB denoting derivation type (0 = public, 1 = private) **/
private final int i;

View File

@ -31,7 +31,7 @@ import static com.google.common.base.Preconditions.checkArgument;
* Bitcoin's privacy system require new keys to be created for each transaction, but managing all these
* keys quickly becomes unwieldy. In particular it becomes hard to back up and distribute them. By having
* a way to derive random-looking but deterministic keys we can make wallet backup simpler and gain the
* ability to hand out {@link ExtendedHierarchicKey}s to other people who can then create new addresses
* ability to hand out {@link DeterministicKey}s to other people who can then create new addresses
* on the fly, without having to contact us.</p>
*
* <p>The hierarchy is started from a single root key, and a location in the tree is given by a path which
@ -44,7 +44,7 @@ public class DeterministicHierarchy implements Serializable {
*/
private static final int MAX_CHILD_DERIVATION_ATTEMPTS = 100;
private final Map<ImmutableList<ChildNumber>, ExtendedHierarchicKey> keys = Maps.newHashMap();
private final Map<ImmutableList<ChildNumber>, DeterministicKey> keys = Maps.newHashMap();
private final ImmutableList<ChildNumber> rootPath;
private final Map<ImmutableList<ChildNumber>, ChildNumber> lastPrivDerivedNumbers = Maps.newHashMap();
private final Map<ImmutableList<ChildNumber>, ChildNumber> lastPubDerivedNumbers = Maps.newHashMap();
@ -53,12 +53,12 @@ public class DeterministicHierarchy implements Serializable {
* Constructs a new hierarchy rooted at the given key. Note that this does not have to be the top of the tree.
* You can construct a DeterministicHierarchy for a subtree of a larger tree that you may not own.
*/
public DeterministicHierarchy(ExtendedHierarchicKey rootKey) {
public DeterministicHierarchy(DeterministicKey rootKey) {
putKey(rootKey);
rootPath = rootKey.getChildNumberPath();
}
private void putKey(ExtendedHierarchicKey key) {
private void putKey(DeterministicKey key) {
keys.put(key.getChildNumberPath(), key);
}
@ -71,14 +71,14 @@ public class DeterministicHierarchy implements Serializable {
* @return next newly created key using the child derivation function
* @throws IllegalArgumentException if create is false and the path was not found.
*/
public ExtendedHierarchicKey get(List<ChildNumber> path, boolean relativePath, boolean create) {
public DeterministicKey get(List<ChildNumber> path, boolean relativePath, boolean create) {
ImmutableList<ChildNumber> absolutePath = relativePath
? ImmutableList.<ChildNumber>builder().addAll(rootPath).addAll(path).build()
: ImmutableList.copyOf(path);
if (!keys.containsKey(absolutePath)) {
checkArgument(create, "No key found for {} path {}.", relativePath ? "relative" : "absolute", path);
checkArgument(absolutePath.size() > 0, "Can't derive the master key: nothing to derive from.");
ExtendedHierarchicKey parent = get(absolutePath.subList(0, absolutePath.size() - 1), relativePath, true);
DeterministicKey parent = get(absolutePath.subList(0, absolutePath.size() - 1), relativePath, true);
putKey(HDKeyDerivation.deriveChildKey(parent, absolutePath.get(absolutePath.size() - 1)));
}
return keys.get(absolutePath);
@ -95,8 +95,8 @@ public class DeterministicHierarchy implements Serializable {
* @return next newly created key using the child derivation funtcion
* @throws IllegalArgumentException if the parent doesn't exist and createParent is false.
*/
public ExtendedHierarchicKey deriveNextChild(ImmutableList<ChildNumber> parentPath, boolean relative, boolean createParent, boolean privateDerivation) {
ExtendedHierarchicKey parent = get(parentPath, relative, createParent);
public DeterministicKey deriveNextChild(ImmutableList<ChildNumber> parentPath, boolean relative, boolean createParent, boolean privateDerivation) {
DeterministicKey parent = get(parentPath, relative, createParent);
int nAttempts = 0;
while (nAttempts++ < MAX_CHILD_DERIVATION_ATTEMPTS) {
try {
@ -125,12 +125,12 @@ public class DeterministicHierarchy implements Serializable {
* @return the requested key.
* @throws IllegalArgumentException if the parent doesn't exist and createParent is false.
*/
public ExtendedHierarchicKey deriveChild(List<ChildNumber> parentPath, boolean relative, boolean createParent, ChildNumber createChildNumber) {
public DeterministicKey deriveChild(List<ChildNumber> parentPath, boolean relative, boolean createParent, ChildNumber createChildNumber) {
return deriveChild(get(parentPath, relative, createParent), createChildNumber);
}
private ExtendedHierarchicKey deriveChild(ExtendedHierarchicKey parent, ChildNumber createChildNumber) {
ExtendedHierarchicKey childKey = HDKeyDerivation.deriveChildKey(parent, createChildNumber);
private DeterministicKey deriveChild(DeterministicKey parent, ChildNumber createChildNumber) {
DeterministicKey childKey = HDKeyDerivation.deriveChildKey(parent, createChildNumber);
putKey(childKey);
return childKey;
}
@ -138,7 +138,7 @@ public class DeterministicHierarchy implements Serializable {
/**
* Returns the root key that the {@link DeterministicHierarchy} was created with.
*/
public ExtendedHierarchicKey getRootKey() {
public DeterministicKey getRootKey() {
return get(rootPath, false, false);
}

View File

@ -24,6 +24,7 @@ import com.google.common.collect.Iterables;
import org.spongycastle.math.ec.ECPoint;
import org.spongycastle.util.encoders.Hex;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.math.BigInteger;
import java.nio.ByteBuffer;
@ -31,27 +32,30 @@ import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* An extended key is a node in a {@link DeterministicHierarchy}. As per
* <a href="https://en.bitcoin.it/wiki/BIP_0032">the BIP 32 specification</a> it is a pair (key, chaincode). If you
* know its path in the tree you can derive more keys from this.
*/
public class ExtendedHierarchicKey implements Serializable {
public static final ChildNumber MASTER_CHILD_NUMBER = new ChildNumber(0);
public class DeterministicKey implements Serializable {
private static final long serialVersionUID = 1L;
private static final Joiner PATH_JOINER = Joiner.on("/");
private final ExtendedHierarchicKey parent;
private final DeterministicKey parent;
private ECPoint publicAsPoint;
private final BigInteger privateAsFieldElement;
private final ImmutableList<ChildNumber> childNumberPath;
/** 32 bytes */
private byte[] chainCode;
private final byte[] chainCode;
ExtendedHierarchicKey(ImmutableList<ChildNumber> childNumberPath, byte[] chainCode, ECPoint publicAsPoint, BigInteger privateKeyFieldElt, ExtendedHierarchicKey parent) {
assert chainCode.length == 32 : chainCode.length;
DeterministicKey(ImmutableList<ChildNumber> childNumberPath, byte[] chainCode,
@Nullable ECPoint publicAsPoint, @Nullable BigInteger privateKeyFieldElt,
@Nullable DeterministicKey parent) {
checkArgument(chainCode.length == 32);
this.parent = parent;
this.childNumberPath = childNumberPath;
this.chainCode = Arrays.copyOf(chainCode, chainCode.length);
@ -73,10 +77,10 @@ public class ExtendedHierarchicKey implements Serializable {
}
/**
* Returns the last element of the path returned by {@link com.google.bitcoin.crypto.hd.ExtendedHierarchicKey#getChildNumberPath()}
* Returns the last element of the path returned by {@link DeterministicKey#getChildNumberPath()}
*/
public ChildNumber getChildNumber() {
return getDepth() == 0 ? MASTER_CHILD_NUMBER : childNumberPath.get(childNumberPath.size() - 1);
return getDepth() == 0 ? ChildNumber.ZERO : childNumberPath.get(childNumberPath.size() - 1);
}
/**
@ -101,7 +105,8 @@ public class ExtendedHierarchicKey implements Serializable {
}
ECPoint getPubPoint() {
if (publicAsPoint == null && privateAsFieldElement != null) {
if (publicAsPoint == null) {
checkNotNull(privateAsFieldElement);
publicAsPoint = HDUtils.getEcParams().getG().multiply(privateAsFieldElement);
}
return HDUtils.compressedCopy(publicAsPoint);
@ -118,14 +123,20 @@ public class ExtendedHierarchicKey implements Serializable {
return Arrays.copyOfRange(getIdentifier(), 0, 4);
}
@Nullable
public BigInteger getPrivAsFieldElement() {
return privateAsFieldElement;
}
public ExtendedHierarchicKey getParent() {
@Nullable
public DeterministicKey getParent() {
return parent;
}
/**
* Returns the private key bytes, if they were provided during construction.
*/
@Nullable
public byte[] getPrivKeyBytes() {
return privateAsFieldElement == null ? null : privateAsFieldElement.toByteArray();
}
@ -135,16 +146,18 @@ public class ExtendedHierarchicKey implements Serializable {
*/
public byte[] getPrivKeyBytes33() {
byte[] bytes33 = new byte[33];
byte[] priv = getPrivKeyBytes();
byte[] priv = checkNotNull(getPrivKeyBytes(), "Private key missing");
System.arraycopy(priv, 0, bytes33, 33 - priv.length, priv.length);
return bytes33;
}
/**
* @return The same key with the private part removed. May return the same instance.
* Returns the same key with the private part removed. May return the same instance.
*/
public ExtendedHierarchicKey getPubOnly() {
return hasPrivate() ? new ExtendedHierarchicKey(getChildNumberPath(), getChainCode(), getPubPoint(), null, getParent() == null ? null : getParent().getPubOnly()) : this;
public DeterministicKey getPubOnly() {
if (!hasPrivate()) return this;
final DeterministicKey parentPub = getParent() == null ? null : getParent().getPubOnly();
return new DeterministicKey(getChildNumberPath(), getChainCode(), getPubPoint(), null, parentPub);
}
public boolean hasPrivate() {

View File

@ -43,7 +43,7 @@ public final class HDKeyDerivation {
*
* @throws HDDerivationException if generated master key is invalid (private key 0 or >= n).
*/
public static ExtendedHierarchicKey createMasterPrivateKey(byte[] seed) throws HDDerivationException {
public static DeterministicKey createMasterPrivateKey(byte[] seed) throws HDDerivationException {
// Calculate I = HMAC-SHA512(key="Bitcoin seed", msg=S)
byte[] i = HDUtils.hmacSha256(MASTER_HMAC_SHA256, seed);
// Split I into two 32-byte sequences, Il and Ir.
@ -52,7 +52,7 @@ public final class HDKeyDerivation {
byte[] il = Arrays.copyOfRange(i, 0, 32);
byte[] ir = Arrays.copyOfRange(i, 32, 64);
Arrays.fill(i, (byte)0);
ExtendedHierarchicKey masterPrivKey = createMasterPrivKeyFromBytes(il, ir);
DeterministicKey masterPrivKey = createMasterPrivKeyFromBytes(il, ir);
Arrays.fill(il, (byte)0);
Arrays.fill(ir, (byte)0);
return masterPrivKey;
@ -61,21 +61,21 @@ public final class HDKeyDerivation {
/**
* @throws HDDerivationException if privKeyBytes is invalid (0 or >= n).
*/
static ExtendedHierarchicKey createMasterPrivKeyFromBytes(byte[] privKeyBytes, byte[] chainCode) throws HDDerivationException {
static DeterministicKey createMasterPrivKeyFromBytes(byte[] privKeyBytes, byte[] chainCode) throws HDDerivationException {
BigInteger privateKeyFieldElt = HDUtils.toBigInteger(privKeyBytes);
assertNonZero(privateKeyFieldElt, "Generated master key is invalid.");
assertLessThanN(privateKeyFieldElt, "Generated master key is invalid.");
return new ExtendedHierarchicKey(ImmutableList.<ChildNumber>of(), chainCode, null, privateKeyFieldElt, null);
return new DeterministicKey(ImmutableList.<ChildNumber>of(), chainCode, null, privateKeyFieldElt, null);
}
public static ExtendedHierarchicKey createMasterPubKeyFromBytes(byte[] pubKeyBytes, byte[] chainCode) {
return new ExtendedHierarchicKey(ImmutableList.<ChildNumber>of(), chainCode, HDUtils.getCurve().decodePoint(pubKeyBytes), null, null);
public static DeterministicKey createMasterPubKeyFromBytes(byte[] pubKeyBytes, byte[] chainCode) {
return new DeterministicKey(ImmutableList.<ChildNumber>of(), chainCode, HDUtils.getCurve().decodePoint(pubKeyBytes), null, null);
}
/**
* @param childNumber the "extended" child number, ie. with the 0x80000000 bit specifying private/public derivation.
*/
public static ExtendedHierarchicKey deriveChildKey(ExtendedHierarchicKey parent, int childNumber) {
public static DeterministicKey deriveChildKey(DeterministicKey parent, int childNumber) {
return deriveChildKey(parent, new ChildNumber(childNumber));
}
@ -83,11 +83,11 @@ public final class HDKeyDerivation {
* @throws HDDerivationException if private derivation is attempted for a public-only parent key, or
* if the resulting derived key is invalid (eg. private key == 0).
*/
public static ExtendedHierarchicKey deriveChildKey(ExtendedHierarchicKey parent, ChildNumber childNumber)
public static DeterministicKey deriveChildKey(DeterministicKey parent, ChildNumber childNumber)
throws HDDerivationException {
RawKeyBytes rawKey = deriveChildKeyBytes(parent, childNumber);
return new ExtendedHierarchicKey(
return new DeterministicKey(
HDUtils.append(parent.getChildNumberPath(), childNumber),
rawKey.chainCode,
parent.hasPrivate() ? null : HDUtils.getCurve().decodePoint(rawKey.keyBytes),
@ -95,7 +95,7 @@ public final class HDKeyDerivation {
parent);
}
private static RawKeyBytes deriveChildKeyBytes(ExtendedHierarchicKey parent, ChildNumber childNumber)
private static RawKeyBytes deriveChildKeyBytes(DeterministicKey parent, ChildNumber childNumber)
throws HDDerivationException {
byte[] parentPublicKey = HDUtils.getBytes(parent.getPubPoint());

View File

@ -126,7 +126,7 @@ public class BIP32Test {
private void testVector(int testCase) throws AddressFormatException {
log.info("======= Test vector {}", testCase);
HDWTestVector tv = tvs[testCase];
ExtendedHierarchicKey masterPrivateKey = HDKeyDerivation.createMasterPrivateKey(Hex.decode(tv.seed));
DeterministicKey masterPrivateKey = HDKeyDerivation.createMasterPrivateKey(Hex.decode(tv.seed));
Assert.assertEquals(testEncode(tv.priv), testEncode(masterPrivateKey.serializePrivB58()));
Assert.assertEquals(testEncode(tv.pub), testEncode(masterPrivateKey.serializePubB58()));
DeterministicHierarchy dh = new DeterministicHierarchy(masterPrivateKey);
@ -135,7 +135,7 @@ public class BIP32Test {
log.info("{}", tc.name);
Assert.assertEquals(tc.name, String.format("Test%d %s", testCase + 1, tc.getPathDescription()));
int depth = tc.path.length - 1;
ExtendedHierarchicKey ehkey = dh.deriveChild(Arrays.asList(tc.path).subList(0, depth), false, true, tc.path[depth]);
DeterministicKey ehkey = dh.deriveChild(Arrays.asList(tc.path).subList(0, depth), false, true, tc.path[depth]);
Assert.assertEquals(testEncode(tc.priv), testEncode(ehkey.serializePrivB58()));
Assert.assertEquals(testEncode(tc.pub), testEncode(ehkey.serializePubB58()));
}

View File

@ -53,56 +53,56 @@ public class ChildKeyDerivationTest {
//////////////////////////////////////////////////////////////////////////
// Start with an extended PRIVATE key
ExtendedHierarchicKey ekprv = HDKeyDerivation.createMasterPrivKeyFromBytes(priv, chain);
DeterministicKey ekprv = HDKeyDerivation.createMasterPrivKeyFromBytes(priv, chain);
// Create two accounts
ExtendedHierarchicKey ekprv_0 = HDKeyDerivation.deriveChildKey(ekprv, 0);
ExtendedHierarchicKey ekprv_1 = HDKeyDerivation.deriveChildKey(ekprv, 1);
DeterministicKey ekprv_0 = HDKeyDerivation.deriveChildKey(ekprv, 0);
DeterministicKey ekprv_1 = HDKeyDerivation.deriveChildKey(ekprv, 1);
// Create internal and external chain on Account 0
ExtendedHierarchicKey ekprv_0_EX = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_EXTERNAL);
ExtendedHierarchicKey ekprv_0_IN = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_INTERNAL);
DeterministicKey ekprv_0_EX = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_EXTERNAL);
DeterministicKey ekprv_0_IN = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_INTERNAL);
// Create three addresses on external chain
ExtendedHierarchicKey ekprv_0_EX_0 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 0);
ExtendedHierarchicKey ekprv_0_EX_1 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 1);
ExtendedHierarchicKey ekprv_0_EX_2 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 2);
DeterministicKey ekprv_0_EX_0 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 0);
DeterministicKey ekprv_0_EX_1 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 1);
DeterministicKey ekprv_0_EX_2 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 2);
// Create three addresses on internal chain
ExtendedHierarchicKey ekprv_0_IN_0 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 0);
ExtendedHierarchicKey ekprv_0_IN_1 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 1);
ExtendedHierarchicKey ekprv_0_IN_2 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 2);
DeterministicKey ekprv_0_IN_0 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 0);
DeterministicKey ekprv_0_IN_1 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 1);
DeterministicKey ekprv_0_IN_2 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 2);
// Now add a few more addresses with very large indices
ExtendedHierarchicKey ekprv_1_IN = HDKeyDerivation.deriveChildKey(ekprv_1, HDW_CHAIN_INTERNAL);
ExtendedHierarchicKey ekprv_1_IN_4095 = HDKeyDerivation.deriveChildKey(ekprv_1_IN, 4095);
DeterministicKey ekprv_1_IN = HDKeyDerivation.deriveChildKey(ekprv_1, HDW_CHAIN_INTERNAL);
DeterministicKey ekprv_1_IN_4095 = HDKeyDerivation.deriveChildKey(ekprv_1_IN, 4095);
// ExtendedHierarchicKey ekprv_1_IN_4bil = HDKeyDerivation.deriveChildKey(ekprv_1_IN, 4294967295L);
//////////////////////////////////////////////////////////////////////////
// Repeat the above with PUBLIC key
ExtendedHierarchicKey ekpub = HDKeyDerivation.createMasterPubKeyFromBytes(HDUtils.toCompressed(pub), chain);
DeterministicKey ekpub = HDKeyDerivation.createMasterPubKeyFromBytes(HDUtils.toCompressed(pub), chain);
// Create two accounts
ExtendedHierarchicKey ekpub_0 = HDKeyDerivation.deriveChildKey(ekpub, 0);
ExtendedHierarchicKey ekpub_1 = HDKeyDerivation.deriveChildKey(ekpub, 1);
DeterministicKey ekpub_0 = HDKeyDerivation.deriveChildKey(ekpub, 0);
DeterministicKey ekpub_1 = HDKeyDerivation.deriveChildKey(ekpub, 1);
// Create internal and external chain on Account 0
ExtendedHierarchicKey ekpub_0_EX = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_EXTERNAL);
ExtendedHierarchicKey ekpub_0_IN = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_INTERNAL);
DeterministicKey ekpub_0_EX = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_EXTERNAL);
DeterministicKey ekpub_0_IN = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_INTERNAL);
// Create three addresses on external chain
ExtendedHierarchicKey ekpub_0_EX_0 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 0);
ExtendedHierarchicKey ekpub_0_EX_1 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 1);
ExtendedHierarchicKey ekpub_0_EX_2 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 2);
DeterministicKey ekpub_0_EX_0 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 0);
DeterministicKey ekpub_0_EX_1 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 1);
DeterministicKey ekpub_0_EX_2 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 2);
// Create three addresses on internal chain
ExtendedHierarchicKey ekpub_0_IN_0 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 0);
ExtendedHierarchicKey ekpub_0_IN_1 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 1);
ExtendedHierarchicKey ekpub_0_IN_2 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 2);
DeterministicKey ekpub_0_IN_0 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 0);
DeterministicKey ekpub_0_IN_1 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 1);
DeterministicKey ekpub_0_IN_2 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 2);
// Now add a few more addresses with very large indices
ExtendedHierarchicKey ekpub_1_IN = HDKeyDerivation.deriveChildKey(ekpub_1, HDW_CHAIN_INTERNAL);
ExtendedHierarchicKey ekpub_1_IN_4095 = HDKeyDerivation.deriveChildKey(ekpub_1_IN, 4095);
DeterministicKey ekpub_1_IN = HDKeyDerivation.deriveChildKey(ekpub_1, HDW_CHAIN_INTERNAL);
DeterministicKey ekpub_1_IN_4095 = HDKeyDerivation.deriveChildKey(ekpub_1_IN, 4095);
// ExtendedHierarchicKey ekpub_1_IN_4bil = HDKeyDerivation.deriveChildKey(ekpub_1_IN, 4294967295L);
assertEquals(hexEncodePub(ekprv.getPubOnly()), hexEncodePub(ekpub));
@ -121,7 +121,7 @@ public class ChildKeyDerivationTest {
}
}
private static String hexEncodePub(ExtendedHierarchicKey pubKey) {
private static String hexEncodePub(DeterministicKey pubKey) {
return hexEncode(pubKey.getPubKeyBytes());
}

View File

@ -30,10 +30,10 @@ public class DeterministicHierarchyTest {
*/
@Test
public void testHierarchy() throws Exception {
ExtendedHierarchicKey m = HDKeyDerivation.createMasterPrivateKey(new SecureRandom().generateSeed(32));
DeterministicKey m = HDKeyDerivation.createMasterPrivateKey(new SecureRandom().generateSeed(32));
for (int iWallet = 0; iWallet < 3; iWallet++) {
ExtendedHierarchicKey walletRootKey = HDKeyDerivation.deriveChildKey(m, iWallet);
DeterministicKey walletRootKey = HDKeyDerivation.deriveChildKey(m, iWallet);
DeterministicKeyGenerator hdWalletKeyGen = new DeterministicKeyGenerator(walletRootKey);
assertEquals(walletRootKey.getChildNumber().getChildNumber(), iWallet);