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

Fix ECKey.equals() and toString() to also include encryptedPrivateKey. Convert to Guava and consolidate at bottom of class.

This commit is contained in:
Andreas Schildbach 2014-07-03 16:31:07 +02:00 committed by Mike Hearn
parent bb40036453
commit d22ee01f8a
4 changed files with 79 additions and 72 deletions

View File

@ -19,6 +19,8 @@ package com.google.bitcoin.core;
import com.google.bitcoin.crypto.*;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Preconditions;
import org.bitcoin.NativeSecp256k1;
import org.bitcoinj.wallet.Protos;
@ -405,32 +407,6 @@ public class ECKey implements EncryptableItem, Serializable {
return pub.isCompressed();
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("pub:").append(Utils.HEX.encode(pub.getEncoded()));
if (creationTimeSeconds != 0) {
b.append(" timestamp:").append(creationTimeSeconds);
}
if (isEncrypted()) {
b.append(" encrypted");
}
return b.toString();
}
/**
* Produce a string rendering of the ECKey INCLUDING the private key.
* Unless you absolutely need the private key it is better for security reasons to just use toString().
*/
public String toStringWithPrivate() {
StringBuilder b = new StringBuilder();
b.append(toString());
if (priv != null) {
b.append(" priv:").append(Utils.HEX.encode(priv.toByteArray()));
}
return b.toString();
}
/**
* Returns the address that corresponds to the public part of this ECKey. Note that an address is derived from
* the RIPEMD-160 hash of the public key and is not the public key itself (which is too large to be convenient).
@ -921,29 +897,6 @@ public class ECKey implements EncryptableItem, Serializable {
creationTimeSeconds = newCreationTimeSeconds;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof ECKey)) return false;
ECKey ecKey = (ECKey) o;
if (creationTimeSeconds != ecKey.creationTimeSeconds) return false;
if (keyCrypter != null ? !keyCrypter.equals(ecKey.keyCrypter) : ecKey.keyCrypter != null) return false;
if (priv != null && !priv.equals(ecKey.priv)) return false;
if (pub != null && !pub.equals(ecKey.pub)) return false;
return true;
}
@Override
public int hashCode() {
// Public keys are random already so we can just use a part of them as the hashcode. Read from the start to
// avoid picking up the type code (compressed vs uncompressed) which is tacked on the end.
byte[] bits = getPubKey();
return (bits[0] & 0xFF) | ((bits[1] & 0xFF) << 8) | ((bits[2] & 0xFF) << 16) | ((bits[3] & 0xFF) << 24);
}
/**
* Create an encrypted private key with the keyCrypter and the AES key supplied.
* This method returns a new encrypted key and leaves the original unchanged.
@ -1083,4 +1036,53 @@ public class ECKey implements EncryptableItem, Serializable {
public static class KeyIsEncryptedException extends MissingPrivateKeyException {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof ECKey)) return false;
ECKey other = (ECKey) o;
return Objects.equal(this.priv, other.priv)
&& Objects.equal(this.pub, other.pub)
&& Objects.equal(this.creationTimeSeconds, other.creationTimeSeconds)
&& Objects.equal(this.keyCrypter, other.keyCrypter)
&& Objects.equal(this.encryptedPrivateKey, other.encryptedPrivateKey);
}
@Override
public int hashCode() {
// Public keys are random already so we can just use a part of them as the hashcode. Read from the start to
// avoid picking up the type code (compressed vs uncompressed) which is tacked on the end.
byte[] bits = getPubKey();
return (bits[0] & 0xFF) | ((bits[1] & 0xFF) << 8) | ((bits[2] & 0xFF) << 16) | ((bits[3] & 0xFF) << 24);
}
@Override
public String toString() {
return toString(false);
}
/**
* Produce a string rendering of the ECKey INCLUDING the private key.
* Unless you absolutely need the private key it is better for security reasons to just use {@link #toString()}.
*/
public String toStringWithPrivate() {
return toString(true);
}
private String toString(boolean includePrivate) {
final ToStringHelper helper = Objects.toStringHelper(this).omitNullValues();
helper.add("pub", Utils.HEX.encode(pub.getEncoded()));
if (includePrivate)
helper.add("priv", Utils.HEX.encode(priv.toByteArray()));
if (creationTimeSeconds > 0)
helper.add("creationTimeSeconds", creationTimeSeconds);
helper.add("keyCrypter", keyCrypter);
if (includePrivate)
helper.add("encryptedPrivateKey", encryptedPrivateKey);
helper.add("isEncrypted", isEncrypted());
return helper.toString();
}
}

View File

@ -17,6 +17,8 @@
package com.google.bitcoin.crypto;
import com.google.bitcoin.core.*;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableList;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.math.ec.ECPoint;
@ -404,6 +406,18 @@ public class DeterministicKey extends ECKey {
}
}
/**
* The creation time of a deterministic key is equal to that of its parent, unless this key is the root of a tree
* in which case the time is stored alongside the key as per normal, see {@link com.google.bitcoin.core.ECKey#getCreationTimeSeconds()}.
*/
@Override
public long getCreationTimeSeconds() {
if (parent != null)
return parent.getCreationTimeSeconds();
else
return super.getCreationTimeSeconds();
}
/**
* Verifies equality of all fields but NOT the parent pointer (thus the same key derived in two separate heirarchy
* objects will equal each other.
@ -412,14 +426,12 @@ public class DeterministicKey extends ECKey {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
DeterministicKey key = (DeterministicKey) o;
DeterministicKey other = (DeterministicKey) o;
if (!Arrays.equals(chainCode, key.chainCode)) return false;
if (!childNumberPath.equals(key.childNumberPath)) return false;
return true;
return super.equals(other)
&& Arrays.equals(this.chainCode, other.chainCode)
&& Objects.equal(this.childNumberPath, other.childNumberPath);
}
@Override
@ -432,19 +444,12 @@ public class DeterministicKey extends ECKey {
@Override
public String toString() {
return String.format("pub:%s chaincode:%s path:%s time:%d", HEX.encode(getPubKey()),
HEX.encode(getChainCode()), getPathAsString(), getCreationTimeSeconds());
}
/**
* The creation time of a deterministic key is equal to that of its parent, unless this key is the root of a tree
* in which case the time is stored alongside the key as per normal, see {@link com.google.bitcoin.core.ECKey#getCreationTimeSeconds()}.
*/
@Override
public long getCreationTimeSeconds() {
if (parent != null)
return parent.getCreationTimeSeconds();
else
return super.getCreationTimeSeconds();
final ToStringHelper helper = Objects.toStringHelper(this).omitNullValues();
helper.add("pub", Utils.HEX.encode(pub.getEncoded()));
helper.add("chainCode", HEX.encode(chainCode));
helper.add("path", getPathAsString());
if (creationTimeSeconds > 0)
helper.add("creationTimeSeconds", creationTimeSeconds);
return helper.toString();
}
}

View File

@ -857,7 +857,7 @@ public class KeyChainGroup {
builder.append(address.toString());
builder.append(" hash160:");
builder.append(Utils.HEX.encode(key.getPubKeyHash()));
builder.append(" ");
builder.append("\n ");
builder.append(includePrivateKeys ? key.toStringWithPrivate() : key.toString());
builder.append("\n");
}

View File

@ -318,8 +318,8 @@ public class ECKeyTest {
public void testToString() throws Exception {
ECKey key = ECKey.fromPrivate(BigInteger.TEN).decompress(); // An example private key.
assertEquals("pub:04a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7893aba425419bc27a3b6c7e693a24c696f794c2ed877a1593cbee53b037368d7", key.toString());
assertEquals("pub:04a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7893aba425419bc27a3b6c7e693a24c696f794c2ed877a1593cbee53b037368d7 priv:0a", key.toStringWithPrivate());
assertEquals("ECKey{pub=04a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7893aba425419bc27a3b6c7e693a24c696f794c2ed877a1593cbee53b037368d7, isEncrypted=false}", key.toString());
assertEquals("ECKey{pub=04a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7893aba425419bc27a3b6c7e693a24c696f794c2ed877a1593cbee53b037368d7, priv=0a, isEncrypted=false}", key.toStringWithPrivate());
}
@Test