mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-12 10:15:52 +00:00
Rename ExtendedHierarchicKey to DeterministicKey. Add annotations and rewrite a bit of code to satisfy static analysis.
This commit is contained in:
parent
50dd5af0c8
commit
000d81d54f
@ -23,6 +23,7 @@ package com.google.bitcoin.crypto.hd;
|
|||||||
*/
|
*/
|
||||||
public class ChildNumber {
|
public class ChildNumber {
|
||||||
public static final int PRIV_BIT = 0x80000000;
|
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) **/
|
/** Integer i as per BIP 32 spec, including the MSB denoting derivation type (0 = public, 1 = private) **/
|
||||||
private final int i;
|
private final int i;
|
||||||
|
@ -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
|
* 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
|
* 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
|
* 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>
|
* 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
|
* <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 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 ImmutableList<ChildNumber> rootPath;
|
||||||
private final Map<ImmutableList<ChildNumber>, ChildNumber> lastPrivDerivedNumbers = Maps.newHashMap();
|
private final Map<ImmutableList<ChildNumber>, ChildNumber> lastPrivDerivedNumbers = Maps.newHashMap();
|
||||||
private final Map<ImmutableList<ChildNumber>, ChildNumber> lastPubDerivedNumbers = 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.
|
* 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.
|
* 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);
|
putKey(rootKey);
|
||||||
rootPath = rootKey.getChildNumberPath();
|
rootPath = rootKey.getChildNumberPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putKey(ExtendedHierarchicKey key) {
|
private void putKey(DeterministicKey key) {
|
||||||
keys.put(key.getChildNumberPath(), 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
|
* @return next newly created key using the child derivation function
|
||||||
* @throws IllegalArgumentException if create is false and the path was not found.
|
* @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> absolutePath = relativePath
|
||||||
? ImmutableList.<ChildNumber>builder().addAll(rootPath).addAll(path).build()
|
? ImmutableList.<ChildNumber>builder().addAll(rootPath).addAll(path).build()
|
||||||
: ImmutableList.copyOf(path);
|
: ImmutableList.copyOf(path);
|
||||||
if (!keys.containsKey(absolutePath)) {
|
if (!keys.containsKey(absolutePath)) {
|
||||||
checkArgument(create, "No key found for {} path {}.", relativePath ? "relative" : "absolute", path);
|
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.");
|
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)));
|
putKey(HDKeyDerivation.deriveChildKey(parent, absolutePath.get(absolutePath.size() - 1)));
|
||||||
}
|
}
|
||||||
return keys.get(absolutePath);
|
return keys.get(absolutePath);
|
||||||
@ -95,8 +95,8 @@ public class DeterministicHierarchy implements Serializable {
|
|||||||
* @return next newly created key using the child derivation funtcion
|
* @return next newly created key using the child derivation funtcion
|
||||||
* @throws IllegalArgumentException if the parent doesn't exist and createParent is false.
|
* @throws IllegalArgumentException if the parent doesn't exist and createParent is false.
|
||||||
*/
|
*/
|
||||||
public ExtendedHierarchicKey deriveNextChild(ImmutableList<ChildNumber> parentPath, boolean relative, boolean createParent, boolean privateDerivation) {
|
public DeterministicKey deriveNextChild(ImmutableList<ChildNumber> parentPath, boolean relative, boolean createParent, boolean privateDerivation) {
|
||||||
ExtendedHierarchicKey parent = get(parentPath, relative, createParent);
|
DeterministicKey parent = get(parentPath, relative, createParent);
|
||||||
int nAttempts = 0;
|
int nAttempts = 0;
|
||||||
while (nAttempts++ < MAX_CHILD_DERIVATION_ATTEMPTS) {
|
while (nAttempts++ < MAX_CHILD_DERIVATION_ATTEMPTS) {
|
||||||
try {
|
try {
|
||||||
@ -125,12 +125,12 @@ public class DeterministicHierarchy implements Serializable {
|
|||||||
* @return the requested key.
|
* @return the requested key.
|
||||||
* @throws IllegalArgumentException if the parent doesn't exist and createParent is false.
|
* @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);
|
return deriveChild(get(parentPath, relative, createParent), createChildNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExtendedHierarchicKey deriveChild(ExtendedHierarchicKey parent, ChildNumber createChildNumber) {
|
private DeterministicKey deriveChild(DeterministicKey parent, ChildNumber createChildNumber) {
|
||||||
ExtendedHierarchicKey childKey = HDKeyDerivation.deriveChildKey(parent, createChildNumber);
|
DeterministicKey childKey = HDKeyDerivation.deriveChildKey(parent, createChildNumber);
|
||||||
putKey(childKey);
|
putKey(childKey);
|
||||||
return childKey;
|
return childKey;
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ public class DeterministicHierarchy implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* Returns the root key that the {@link DeterministicHierarchy} was created with.
|
* Returns the root key that the {@link DeterministicHierarchy} was created with.
|
||||||
*/
|
*/
|
||||||
public ExtendedHierarchicKey getRootKey() {
|
public DeterministicKey getRootKey() {
|
||||||
return get(rootPath, false, false);
|
return get(rootPath, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import com.google.common.collect.Iterables;
|
|||||||
import org.spongycastle.math.ec.ECPoint;
|
import org.spongycastle.math.ec.ECPoint;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -31,27 +32,30 @@ import java.text.MessageFormat;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
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
|
* 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
|
* <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.
|
* know its path in the tree you can derive more keys from this.
|
||||||
*/
|
*/
|
||||||
public class ExtendedHierarchicKey implements Serializable {
|
public class DeterministicKey implements Serializable {
|
||||||
public static final ChildNumber MASTER_CHILD_NUMBER = new ChildNumber(0);
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final Joiner PATH_JOINER = Joiner.on("/");
|
private static final Joiner PATH_JOINER = Joiner.on("/");
|
||||||
|
|
||||||
private final ExtendedHierarchicKey parent;
|
private final DeterministicKey parent;
|
||||||
private ECPoint publicAsPoint;
|
private ECPoint publicAsPoint;
|
||||||
private final BigInteger privateAsFieldElement;
|
private final BigInteger privateAsFieldElement;
|
||||||
private final ImmutableList<ChildNumber> childNumberPath;
|
private final ImmutableList<ChildNumber> childNumberPath;
|
||||||
|
|
||||||
/** 32 bytes */
|
/** 32 bytes */
|
||||||
private byte[] chainCode;
|
private final byte[] chainCode;
|
||||||
|
|
||||||
ExtendedHierarchicKey(ImmutableList<ChildNumber> childNumberPath, byte[] chainCode, ECPoint publicAsPoint, BigInteger privateKeyFieldElt, ExtendedHierarchicKey parent) {
|
DeterministicKey(ImmutableList<ChildNumber> childNumberPath, byte[] chainCode,
|
||||||
assert chainCode.length == 32 : chainCode.length;
|
@Nullable ECPoint publicAsPoint, @Nullable BigInteger privateKeyFieldElt,
|
||||||
|
@Nullable DeterministicKey parent) {
|
||||||
|
checkArgument(chainCode.length == 32);
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.childNumberPath = childNumberPath;
|
this.childNumberPath = childNumberPath;
|
||||||
this.chainCode = Arrays.copyOf(chainCode, chainCode.length);
|
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() {
|
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() {
|
ECPoint getPubPoint() {
|
||||||
if (publicAsPoint == null && privateAsFieldElement != null) {
|
if (publicAsPoint == null) {
|
||||||
|
checkNotNull(privateAsFieldElement);
|
||||||
publicAsPoint = HDUtils.getEcParams().getG().multiply(privateAsFieldElement);
|
publicAsPoint = HDUtils.getEcParams().getG().multiply(privateAsFieldElement);
|
||||||
}
|
}
|
||||||
return HDUtils.compressedCopy(publicAsPoint);
|
return HDUtils.compressedCopy(publicAsPoint);
|
||||||
@ -118,14 +123,20 @@ public class ExtendedHierarchicKey implements Serializable {
|
|||||||
return Arrays.copyOfRange(getIdentifier(), 0, 4);
|
return Arrays.copyOfRange(getIdentifier(), 0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public BigInteger getPrivAsFieldElement() {
|
public BigInteger getPrivAsFieldElement() {
|
||||||
return privateAsFieldElement;
|
return privateAsFieldElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExtendedHierarchicKey getParent() {
|
@Nullable
|
||||||
|
public DeterministicKey getParent() {
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the private key bytes, if they were provided during construction.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
public byte[] getPrivKeyBytes() {
|
public byte[] getPrivKeyBytes() {
|
||||||
return privateAsFieldElement == null ? null : privateAsFieldElement.toByteArray();
|
return privateAsFieldElement == null ? null : privateAsFieldElement.toByteArray();
|
||||||
}
|
}
|
||||||
@ -135,16 +146,18 @@ public class ExtendedHierarchicKey implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public byte[] getPrivKeyBytes33() {
|
public byte[] getPrivKeyBytes33() {
|
||||||
byte[] bytes33 = new byte[33];
|
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);
|
System.arraycopy(priv, 0, bytes33, 33 - priv.length, priv.length);
|
||||||
return bytes33;
|
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() {
|
public DeterministicKey getPubOnly() {
|
||||||
return hasPrivate() ? new ExtendedHierarchicKey(getChildNumberPath(), getChainCode(), getPubPoint(), null, getParent() == null ? null : getParent().getPubOnly()) : this;
|
if (!hasPrivate()) return this;
|
||||||
|
final DeterministicKey parentPub = getParent() == null ? null : getParent().getPubOnly();
|
||||||
|
return new DeterministicKey(getChildNumberPath(), getChainCode(), getPubPoint(), null, parentPub);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPrivate() {
|
public boolean hasPrivate() {
|
@ -43,7 +43,7 @@ public final class HDKeyDerivation {
|
|||||||
*
|
*
|
||||||
* @throws HDDerivationException if generated master key is invalid (private key 0 or >= n).
|
* @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)
|
// Calculate I = HMAC-SHA512(key="Bitcoin seed", msg=S)
|
||||||
byte[] i = HDUtils.hmacSha256(MASTER_HMAC_SHA256, seed);
|
byte[] i = HDUtils.hmacSha256(MASTER_HMAC_SHA256, seed);
|
||||||
// Split I into two 32-byte sequences, Il and Ir.
|
// 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[] il = Arrays.copyOfRange(i, 0, 32);
|
||||||
byte[] ir = Arrays.copyOfRange(i, 32, 64);
|
byte[] ir = Arrays.copyOfRange(i, 32, 64);
|
||||||
Arrays.fill(i, (byte)0);
|
Arrays.fill(i, (byte)0);
|
||||||
ExtendedHierarchicKey masterPrivKey = createMasterPrivKeyFromBytes(il, ir);
|
DeterministicKey masterPrivKey = createMasterPrivKeyFromBytes(il, ir);
|
||||||
Arrays.fill(il, (byte)0);
|
Arrays.fill(il, (byte)0);
|
||||||
Arrays.fill(ir, (byte)0);
|
Arrays.fill(ir, (byte)0);
|
||||||
return masterPrivKey;
|
return masterPrivKey;
|
||||||
@ -61,21 +61,21 @@ public final class HDKeyDerivation {
|
|||||||
/**
|
/**
|
||||||
* @throws HDDerivationException if privKeyBytes is invalid (0 or >= n).
|
* @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);
|
BigInteger privateKeyFieldElt = HDUtils.toBigInteger(privKeyBytes);
|
||||||
assertNonZero(privateKeyFieldElt, "Generated master key is invalid.");
|
assertNonZero(privateKeyFieldElt, "Generated master key is invalid.");
|
||||||
assertLessThanN(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) {
|
public static DeterministicKey createMasterPubKeyFromBytes(byte[] pubKeyBytes, byte[] chainCode) {
|
||||||
return new ExtendedHierarchicKey(ImmutableList.<ChildNumber>of(), chainCode, HDUtils.getCurve().decodePoint(pubKeyBytes), null, null);
|
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.
|
* @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));
|
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
|
* @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).
|
* 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 {
|
throws HDDerivationException {
|
||||||
|
|
||||||
RawKeyBytes rawKey = deriveChildKeyBytes(parent, childNumber);
|
RawKeyBytes rawKey = deriveChildKeyBytes(parent, childNumber);
|
||||||
return new ExtendedHierarchicKey(
|
return new DeterministicKey(
|
||||||
HDUtils.append(parent.getChildNumberPath(), childNumber),
|
HDUtils.append(parent.getChildNumberPath(), childNumber),
|
||||||
rawKey.chainCode,
|
rawKey.chainCode,
|
||||||
parent.hasPrivate() ? null : HDUtils.getCurve().decodePoint(rawKey.keyBytes),
|
parent.hasPrivate() ? null : HDUtils.getCurve().decodePoint(rawKey.keyBytes),
|
||||||
@ -95,7 +95,7 @@ public final class HDKeyDerivation {
|
|||||||
parent);
|
parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RawKeyBytes deriveChildKeyBytes(ExtendedHierarchicKey parent, ChildNumber childNumber)
|
private static RawKeyBytes deriveChildKeyBytes(DeterministicKey parent, ChildNumber childNumber)
|
||||||
throws HDDerivationException {
|
throws HDDerivationException {
|
||||||
|
|
||||||
byte[] parentPublicKey = HDUtils.getBytes(parent.getPubPoint());
|
byte[] parentPublicKey = HDUtils.getBytes(parent.getPubPoint());
|
||||||
|
@ -126,7 +126,7 @@ public class BIP32Test {
|
|||||||
private void testVector(int testCase) throws AddressFormatException {
|
private void testVector(int testCase) throws AddressFormatException {
|
||||||
log.info("======= Test vector {}", testCase);
|
log.info("======= Test vector {}", testCase);
|
||||||
HDWTestVector tv = tvs[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.priv), testEncode(masterPrivateKey.serializePrivB58()));
|
||||||
Assert.assertEquals(testEncode(tv.pub), testEncode(masterPrivateKey.serializePubB58()));
|
Assert.assertEquals(testEncode(tv.pub), testEncode(masterPrivateKey.serializePubB58()));
|
||||||
DeterministicHierarchy dh = new DeterministicHierarchy(masterPrivateKey);
|
DeterministicHierarchy dh = new DeterministicHierarchy(masterPrivateKey);
|
||||||
@ -135,7 +135,7 @@ public class BIP32Test {
|
|||||||
log.info("{}", tc.name);
|
log.info("{}", tc.name);
|
||||||
Assert.assertEquals(tc.name, String.format("Test%d %s", testCase + 1, tc.getPathDescription()));
|
Assert.assertEquals(tc.name, String.format("Test%d %s", testCase + 1, tc.getPathDescription()));
|
||||||
int depth = tc.path.length - 1;
|
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.priv), testEncode(ehkey.serializePrivB58()));
|
||||||
Assert.assertEquals(testEncode(tc.pub), testEncode(ehkey.serializePubB58()));
|
Assert.assertEquals(testEncode(tc.pub), testEncode(ehkey.serializePubB58()));
|
||||||
}
|
}
|
||||||
|
@ -53,56 +53,56 @@ public class ChildKeyDerivationTest {
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Start with an extended PRIVATE key
|
// Start with an extended PRIVATE key
|
||||||
ExtendedHierarchicKey ekprv = HDKeyDerivation.createMasterPrivKeyFromBytes(priv, chain);
|
DeterministicKey ekprv = HDKeyDerivation.createMasterPrivKeyFromBytes(priv, chain);
|
||||||
|
|
||||||
// Create two accounts
|
// Create two accounts
|
||||||
ExtendedHierarchicKey ekprv_0 = HDKeyDerivation.deriveChildKey(ekprv, 0);
|
DeterministicKey ekprv_0 = HDKeyDerivation.deriveChildKey(ekprv, 0);
|
||||||
ExtendedHierarchicKey ekprv_1 = HDKeyDerivation.deriveChildKey(ekprv, 1);
|
DeterministicKey ekprv_1 = HDKeyDerivation.deriveChildKey(ekprv, 1);
|
||||||
|
|
||||||
// Create internal and external chain on Account 0
|
// Create internal and external chain on Account 0
|
||||||
ExtendedHierarchicKey ekprv_0_EX = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_EXTERNAL);
|
DeterministicKey ekprv_0_EX = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_EXTERNAL);
|
||||||
ExtendedHierarchicKey ekprv_0_IN = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_INTERNAL);
|
DeterministicKey ekprv_0_IN = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_INTERNAL);
|
||||||
|
|
||||||
// Create three addresses on external chain
|
// Create three addresses on external chain
|
||||||
ExtendedHierarchicKey ekprv_0_EX_0 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 0);
|
DeterministicKey ekprv_0_EX_0 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 0);
|
||||||
ExtendedHierarchicKey ekprv_0_EX_1 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 1);
|
DeterministicKey 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_2 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 2);
|
||||||
|
|
||||||
// Create three addresses on internal chain
|
// Create three addresses on internal chain
|
||||||
ExtendedHierarchicKey ekprv_0_IN_0 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 0);
|
DeterministicKey ekprv_0_IN_0 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 0);
|
||||||
ExtendedHierarchicKey ekprv_0_IN_1 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 1);
|
DeterministicKey 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_2 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 2);
|
||||||
|
|
||||||
// Now add a few more addresses with very large indices
|
// Now add a few more addresses with very large indices
|
||||||
ExtendedHierarchicKey ekprv_1_IN = HDKeyDerivation.deriveChildKey(ekprv_1, HDW_CHAIN_INTERNAL);
|
DeterministicKey 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_4095 = HDKeyDerivation.deriveChildKey(ekprv_1_IN, 4095);
|
||||||
// ExtendedHierarchicKey ekprv_1_IN_4bil = HDKeyDerivation.deriveChildKey(ekprv_1_IN, 4294967295L);
|
// ExtendedHierarchicKey ekprv_1_IN_4bil = HDKeyDerivation.deriveChildKey(ekprv_1_IN, 4294967295L);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Repeat the above with PUBLIC key
|
// 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
|
// Create two accounts
|
||||||
ExtendedHierarchicKey ekpub_0 = HDKeyDerivation.deriveChildKey(ekpub, 0);
|
DeterministicKey ekpub_0 = HDKeyDerivation.deriveChildKey(ekpub, 0);
|
||||||
ExtendedHierarchicKey ekpub_1 = HDKeyDerivation.deriveChildKey(ekpub, 1);
|
DeterministicKey ekpub_1 = HDKeyDerivation.deriveChildKey(ekpub, 1);
|
||||||
|
|
||||||
// Create internal and external chain on Account 0
|
// Create internal and external chain on Account 0
|
||||||
ExtendedHierarchicKey ekpub_0_EX = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_EXTERNAL);
|
DeterministicKey ekpub_0_EX = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_EXTERNAL);
|
||||||
ExtendedHierarchicKey ekpub_0_IN = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_INTERNAL);
|
DeterministicKey ekpub_0_IN = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_INTERNAL);
|
||||||
|
|
||||||
// Create three addresses on external chain
|
// Create three addresses on external chain
|
||||||
ExtendedHierarchicKey ekpub_0_EX_0 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 0);
|
DeterministicKey ekpub_0_EX_0 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 0);
|
||||||
ExtendedHierarchicKey ekpub_0_EX_1 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 1);
|
DeterministicKey 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_2 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 2);
|
||||||
|
|
||||||
// Create three addresses on internal chain
|
// Create three addresses on internal chain
|
||||||
ExtendedHierarchicKey ekpub_0_IN_0 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 0);
|
DeterministicKey ekpub_0_IN_0 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 0);
|
||||||
ExtendedHierarchicKey ekpub_0_IN_1 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 1);
|
DeterministicKey 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_2 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 2);
|
||||||
|
|
||||||
// Now add a few more addresses with very large indices
|
// Now add a few more addresses with very large indices
|
||||||
ExtendedHierarchicKey ekpub_1_IN = HDKeyDerivation.deriveChildKey(ekpub_1, HDW_CHAIN_INTERNAL);
|
DeterministicKey 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_4095 = HDKeyDerivation.deriveChildKey(ekpub_1_IN, 4095);
|
||||||
// ExtendedHierarchicKey ekpub_1_IN_4bil = HDKeyDerivation.deriveChildKey(ekpub_1_IN, 4294967295L);
|
// ExtendedHierarchicKey ekpub_1_IN_4bil = HDKeyDerivation.deriveChildKey(ekpub_1_IN, 4294967295L);
|
||||||
|
|
||||||
assertEquals(hexEncodePub(ekprv.getPubOnly()), hexEncodePub(ekpub));
|
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());
|
return hexEncode(pubKey.getPubKeyBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,10 +30,10 @@ public class DeterministicHierarchyTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testHierarchy() throws Exception {
|
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++) {
|
for (int iWallet = 0; iWallet < 3; iWallet++) {
|
||||||
ExtendedHierarchicKey walletRootKey = HDKeyDerivation.deriveChildKey(m, iWallet);
|
DeterministicKey walletRootKey = HDKeyDerivation.deriveChildKey(m, iWallet);
|
||||||
DeterministicKeyGenerator hdWalletKeyGen = new DeterministicKeyGenerator(walletRootKey);
|
DeterministicKeyGenerator hdWalletKeyGen = new DeterministicKeyGenerator(walletRootKey);
|
||||||
assertEquals(walletRootKey.getChildNumber().getChildNumber(), iWallet);
|
assertEquals(walletRootKey.getChildNumber().getChildNumber(), iWallet);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user