Be lenient in parsing tx confidence protobuf, store pubkeys, cleanup

This commit is contained in:
Miron Cuperman 2012-01-26 10:43:15 -08:00
parent 1c28bd3972
commit 69ee4c7729
9 changed files with 350 additions and 208 deletions

View file

@ -26,14 +26,24 @@ package wallet;
option java_package = "org.bitcoinj.wallet"; option java_package = "org.bitcoinj.wallet";
option java_outer_classname = "Protos"; option java_outer_classname = "Protos";
/**
* A key use to control Bitcoin spending
*
* Either the private key, the public key or both may be present. It is recommended that
* if the private key is provided that the public key is provided too because deriving it is slow.
*
* If only the public key is provided, the key can only be used to watch the blockchain and verify
* transactions, and not for spending.
*/
message Key { message Key {
enum Type { enum Type {
ORIGINAL = 1; // Original bitcoin secp256k1 curve ORIGINAL = 1; // Original bitcoin secp256k1 curve
} }
required bytes private_key = 1; // integer representation of the EC private key required Type type = 1;
required Type type = 2; optional bytes private_key = 2; // integer representation of the EC private key
optional string label = 3; // for presentation purposes optional bytes public_key = 3; // integer representation of the EC public key
optional int64 creation_timestamp = 4; // datetime stored as millis since epoch. optional string label = 4; // for presentation purposes
optional int64 creation_timestamp = 5; // datetime stored as millis since epoch.
} }
message TransactionInput { message TransactionInput {
@ -53,20 +63,30 @@ message TransactionOutput {
// if spent, the index of the transaction output of the transaction doing the spend // if spent, the index of the transaction output of the transaction doing the spend
} }
/**
* A description of the confidence we have that a transaction cannot be reversed in the future.
*
* Parsing should be lenient, since this could change for different applications yet we should
* maintain backward compatibility.
*/
message TransactionConfidence { message TransactionConfidence {
enum Type { enum Type {
UNKNOWN = 0; UNKNOWN = 0;
BUILDING = 1; BUILDING = 1; // In best chain. If and only if appeared_at_height is present.
NOT_SEEN_IN_CHAIN = 2; NOT_SEEN_IN_CHAIN = 2; // Pending inclusion in best chain.
NOT_IN_BEST_CHAIN = 3; NOT_IN_BEST_CHAIN = 3; // In non-best chain, pending inclusion in best chain.
OVERRIDDEN_BY_DOUBLE_SPEND = 4; OVERRIDDEN_BY_DOUBLE_SPEND = 4; // If and only if overriding_transaction is present.
} }
required Type type = 1; // This is optional in case we add confidence types to prevent parse errors - backwards compatible.
optional Type type = 1;
optional int32 appeared_at_height = 2; optional int32 appeared_at_height = 2;
optional bytes overriding_transaction = 3; optional bytes overriding_transaction = 3; // Hash of tx. Should be in this wallet.
} }
/** A bitcoin transaction */
message Transaction { message Transaction {
/** /**
* This is a bitfield oriented enum, with the following bits: * This is a bitfield oriented enum, with the following bits:
@ -107,6 +127,7 @@ message Transaction {
// Sha256Hash of block in block chain in which this transaction appears // Sha256Hash of block in block chain in which this transaction appears
} }
/** An extension to the wallet */
message Extension { message Extension {
required string id = 1; // like org.whatever.foo.bar required string id = 1; // like org.whatever.foo.bar
required bytes data = 2; required bytes data = 2;
@ -116,6 +137,7 @@ message Extension {
required bool mandatory = 3; required bool mandatory = 3;
} }
/** A bitcoin wallet */
message Wallet { message Wallet {
required string network_identifier = 1; // the network used by this wallet required string network_identifier = 1; // the network used by this wallet
// org.bitcoin.production = production network (Satoshi genesis block) // org.bitcoin.production = production network (Satoshi genesis block)

View file

@ -49,6 +49,6 @@ public class DumpedPrivateKey extends VersionedChecksummedBytes {
* Returns an ECKey created from this encoded private key. * Returns an ECKey created from this encoded private key.
*/ */
public ECKey getKey() { public ECKey getKey() {
return new ECKey(new BigInteger(1, bytes), null); return new ECKey(new BigInteger(1, bytes));
} }
} }

View file

@ -85,7 +85,7 @@ public class ECKey implements Serializable {
* reference implementation in its wallet. Note that this is slow because it requires an EC point multiply. * reference implementation in its wallet. Note that this is slow because it requires an EC point multiply.
*/ */
public static ECKey fromASN1(byte[] asn1privkey) { public static ECKey fromASN1(byte[] asn1privkey) {
return new ECKey(extractPrivateKeyFromASN1(asn1privkey), null); return new ECKey(extractPrivateKeyFromASN1(asn1privkey));
} }
/** /**
@ -122,7 +122,7 @@ public class ECKey implements Serializable {
* the public key already correctly matches the public key. If only the public key is supplied, this ECKey cannot * the public key already correctly matches the public key. If only the public key is supplied, this ECKey cannot
* be used for signing. * be used for signing.
*/ */
public ECKey(BigInteger privKey, BigInteger pubKey) { private ECKey(BigInteger privKey, byte[] pubKey) {
this.priv = privKey; this.priv = privKey;
this.pub = null; this.pub = null;
if (pubKey == null && privKey != null) { if (pubKey == null && privKey != null) {
@ -132,22 +132,27 @@ public class ECKey implements Serializable {
// We expect the pubkey to be in regular encoded form, just as a BigInteger. Therefore the first byte is // We expect the pubkey to be in regular encoded form, just as a BigInteger. Therefore the first byte is
// a special marker byte. // a special marker byte.
// TODO: This is probably not a useful API and may be confusing. // TODO: This is probably not a useful API and may be confusing.
this.pub = Utils.bigIntegerToBytes(pubKey, 65); this.pub = pubKey;
} }
} }
/** Creates an ECKey given the private key only. The public key is calculated from it (this is slow) */
public ECKey(BigInteger privKey) {
this(privKey, (byte[])null);
}
/** A constructor variant with BigInteger pubkey. See {@link ECKey#ECKey(BigInteger, byte[])}. */
public ECKey(BigInteger privKey, BigInteger pubKey) {
this(privKey, Utils.bigIntegerToBytes(pubKey, 65));
}
/** /**
* Creates an ECKey given only the private key bytes. This is the same as using the BigInteger constructor, but * Creates an ECKey given only the private key bytes. This is the same as using the BigInteger constructor, but
* is more convenient if you are importing a key from elsewhere. The public key will be automatically derived * is more convenient if you are importing a key from elsewhere. The public key will be automatically derived
* from the private key. Same as calling {@link ECKey#fromPrivKeyBytes(byte[])}. * from the private key. Same as calling {@link ECKey#fromPrivKeyBytes(byte[])}.
*/ */
public ECKey(byte[] privKeyBytes, byte[] pubKeyBytes) { public ECKey(byte[] privKeyBytes, byte[] pubKey) {
priv = privKeyBytes == null ? null : new BigInteger(1, privKeyBytes); this(privKeyBytes == null ? null : new BigInteger(1, privKeyBytes), pubKey);
pub = pubKeyBytes;
if (pub == null && priv != null) {
// Derive public from private.
pub = publicKeyFromPrivate(priv);
}
} }
/** /**
@ -284,10 +289,6 @@ public class ECKey implements Serializable {
return Utils.bigIntegerToBytes(priv, 32); return Utils.bigIntegerToBytes(priv, 32);
} }
public static ECKey fromPrivKeyBytes(byte[] bytes) {
return new ECKey(new BigInteger(1, bytes), null);
}
/** /**
* Exports the private key in the form used by the Satoshi client "dumpprivkey" and "importprivkey" commands. Use * Exports the private key in the form used by the Satoshi client "dumpprivkey" and "importprivkey" commands. Use
* the {@link com.google.bitcoin.core.DumpedPrivateKey#toString()} method to get the string. * the {@link com.google.bitcoin.core.DumpedPrivateKey#toString()} method to get the string.

View file

@ -707,7 +707,7 @@ public class Transaction extends ChildMessage implements Serializable {
return confidence; return confidence;
} }
/** Check if the transaction has a known confidence */
public boolean hasConfidence() { public boolean hasConfidence() {
return confidence != null && confidence.getConfidenceType() != TransactionConfidence.ConfidenceType.UNKNOWN; return confidence != null && confidence.getConfidenceType() != TransactionConfidence.ConfidenceType.UNKNOWN;
} }

View file

@ -70,6 +70,9 @@ public class Utils {
* @return 32 byte long array. * @return 32 byte long array.
*/ */
public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) { public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) {
if (b == null) {
return null;
}
byte[] bytes = new byte[numBytes]; byte[] bytes = new byte[numBytes];
byte[] biBytes = b.toByteArray(); byte[] biBytes = b.toByteArray();
int start = (biBytes.length == numBytes + 1) ? 1 : 0; int start = (biBytes.length == numBytes + 1) ? 1 : 0;

View file

@ -44,7 +44,7 @@ public class PrivateKeys {
key = dumpedPrivateKey.getKey(); key = dumpedPrivateKey.getKey();
} else { } else {
BigInteger privKey = Base58.decodeToBigInteger(args[0]); BigInteger privKey = Base58.decodeToBigInteger(args[0]);
key = new ECKey(privKey, null); key = new ECKey(privKey);
} }
System.out.println("Address from private key is: " + key.toAddress(params).toString()); System.out.println("Address from private key is: " + key.toAddress(params).toString());
// And the address ... // And the address ...

View file

@ -31,6 +31,8 @@ import com.google.protobuf.ByteString;
import com.google.protobuf.TextFormat; import com.google.protobuf.TextFormat;
import org.bitcoinj.wallet.Protos; import org.bitcoinj.wallet.Protos;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -46,6 +48,8 @@ import java.util.Map;
* @author Miron Cuperman * @author Miron Cuperman
*/ */
public class WalletProtobufSerializer { public class WalletProtobufSerializer {
private static final Logger log = LoggerFactory.getLogger(WalletProtobufSerializer.class);
// Used for de-serialization // Used for de-serialization
private Map<ByteString, Transaction> txMap; private Map<ByteString, Transaction> txMap;
@ -82,7 +86,9 @@ public class WalletProtobufSerializer {
// .setCreationTimestamp() TODO // .setCreationTimestamp() TODO
// .setLabel() TODO // .setLabel() TODO
.setType(Protos.Key.Type.ORIGINAL) .setType(Protos.Key.Type.ORIGINAL)
.setPrivateKey(ByteString.copyFrom(key.getPrivKeyBytes()))); .setPrivateKey(ByteString.copyFrom(key.getPrivKeyBytes()))
.setPublicKey(ByteString.copyFrom(key.getPubKey()))
);
} }
return walletBuilder.build(); return walletBuilder.build();
} }
@ -126,9 +132,11 @@ public class WalletProtobufSerializer {
.setValue(output.getValue().longValue()); .setValue(output.getValue().longValue());
final TransactionInput spentBy = output.getSpentBy(); final TransactionInput spentBy = output.getSpentBy();
if (spentBy != null) { if (spentBy != null) {
Sha256Hash spendingHash = spentBy.getParentTransaction().getHash();
outputBuilder outputBuilder
.setSpentByTransactionHash(ByteString.copyFrom(spentBy.getParentTransaction().getHash().getBytes())) .setSpentByTransactionHash(hashToByteString(spendingHash))
.setSpentByTransactionIndex(spentBy.getParentTransaction().getInputs().indexOf(spentBy)); .setSpentByTransactionIndex(
spentBy.getParentTransaction().getInputs().indexOf(spentBy));
} }
txBuilder.addTransactionOutput(outputBuilder); txBuilder.addTransactionOutput(outputBuilder);
} }
@ -136,7 +144,7 @@ public class WalletProtobufSerializer {
// Handle which blocks tx was seen in // Handle which blocks tx was seen in
if (tx.getAppearsInHashes() != null) { if (tx.getAppearsInHashes() != null) {
for (Sha256Hash hash : tx.getAppearsInHashes()) { for (Sha256Hash hash : tx.getAppearsInHashes()) {
txBuilder.addBlockHash(ByteString.copyFrom(hash.getBytes())); txBuilder.addBlockHash(hashToByteString(hash));
} }
} }
@ -145,20 +153,33 @@ public class WalletProtobufSerializer {
Protos.TransactionConfidence.Builder confidenceBuilder = Protos.TransactionConfidence.Builder confidenceBuilder =
Protos.TransactionConfidence.newBuilder(); Protos.TransactionConfidence.newBuilder();
confidenceBuilder.setType(Protos.TransactionConfidence.Type.valueOf(confidence.getConfidenceType().getValue())); writeConfidence(txBuilder, confidence, confidenceBuilder);
if (confidence.getConfidenceType() == ConfidenceType.BUILDING) {
confidenceBuilder.setAppearedAtHeight(confidence.getAppearedAtChainHeight());
}
if (confidence.getConfidenceType() == ConfidenceType.OVERRIDDEN_BY_DOUBLE_SPEND) {
confidenceBuilder.setOverridingTransaction(ByteString.copyFrom(confidence.getOverridingTransaction().getHash().getBytes()));
}
txBuilder.setConfidence(confidenceBuilder);
} }
return txBuilder.build(); return txBuilder.build();
} }
private static void writeConfidence(
Protos.Transaction.Builder txBuilder,
TransactionConfidence confidence,
Protos.TransactionConfidence.Builder confidenceBuilder) {
confidenceBuilder.setType(
Protos.TransactionConfidence.Type.valueOf(confidence.getConfidenceType().getValue()));
if (confidence.getConfidenceType() == ConfidenceType.BUILDING) {
confidenceBuilder.setAppearedAtHeight(confidence.getAppearedAtChainHeight());
}
if (confidence.getConfidenceType() == ConfidenceType.OVERRIDDEN_BY_DOUBLE_SPEND) {
Sha256Hash overridingHash = confidence.getOverridingTransaction().getHash();
confidenceBuilder.setOverridingTransaction(hashToByteString(overridingHash));
}
txBuilder.setConfidence(confidenceBuilder);
}
private static ByteString hashToByteString(Sha256Hash hash) {
return ByteString.copyFrom(hash.getBytes());
}
public static Wallet readWallet(InputStream input, NetworkParameters params) public static Wallet readWallet(InputStream input, NetworkParameters params)
throws IOException { throws IOException {
WalletProtobufSerializer serializer = new WalletProtobufSerializer(); WalletProtobufSerializer serializer = new WalletProtobufSerializer();
@ -175,7 +196,12 @@ public class WalletProtobufSerializer {
if (keyProto.getType() != Protos.Key.Type.ORIGINAL) { if (keyProto.getType() != Protos.Key.Type.ORIGINAL) {
throw new IllegalArgumentException("Unknown key type in wallet"); throw new IllegalArgumentException("Unknown key type in wallet");
} }
wallet.addKey(ECKey.fromPrivKeyBytes(keyProto.getPrivateKey().toByteArray())); if (!keyProto.hasPrivateKey()) {
throw new IllegalArgumentException("Don't know how to handle pubkey-only keys");
}
byte[] pubKey = keyProto.hasPublicKey() ? keyProto.getPublicKey().toByteArray() : null;
wallet.addKey(new ECKey(keyProto.getPrivateKey().toByteArray(), pubKey));
} }
// Read all transactions and create outputs // Read all transactions and create outputs
@ -205,7 +231,9 @@ public class WalletProtobufSerializer {
private void readTransaction(Protos.Transaction txProto, NetworkParameters params) { private void readTransaction(Protos.Transaction txProto, NetworkParameters params) {
Transaction tx = new Transaction(params, txProto.getVersion(), new Sha256Hash(txProto.getHash().toByteArray())); Transaction tx =
new Transaction(params, txProto.getVersion(),
new Sha256Hash(txProto.getHash().toByteArray()));
if (txProto.hasUpdatedAt()) if (txProto.hasUpdatedAt())
tx.setUpdateTime(new Date(txProto.getUpdatedAt())); tx.setUpdateTime(new Date(txProto.getUpdatedAt()));
@ -270,17 +298,43 @@ public class WalletProtobufSerializer {
if(txProto.hasConfidence()) { if(txProto.hasConfidence()) {
Protos.TransactionConfidence confidenceProto = txProto.getConfidence(); Protos.TransactionConfidence confidenceProto = txProto.getConfidence();
TransactionConfidence confidence = tx.getConfidence(); TransactionConfidence confidence = tx.getConfidence();
confidence.setConfidenceType(TransactionConfidence.ConfidenceType.valueOf(confidenceProto.getType().getNumber())); readConfidence(tx, confidenceProto, confidence);
if (confidenceProto.hasAppearedAtHeight()) {
assert confidence.getConfidenceType() == ConfidenceType.BUILDING;
confidence.setAppearedAtChainHeight(confidenceProto.getAppearedAtHeight());
}
if (confidenceProto.hasOverridingTransaction()) {
assert confidence.getConfidenceType() == ConfidenceType.OVERRIDDEN_BY_DOUBLE_SPEND;
confidence.setOverridingTransaction(txMap.get(confidenceProto.getOverridingTransaction()));
}
} }
return new WalletTransaction(pool, tx); return new WalletTransaction(pool, tx);
} }
private void readConfidence(
Transaction tx, Protos.TransactionConfidence confidenceProto,
TransactionConfidence confidence) {
// We are lenient here because tx confidence is not an essential part of the wallet.
// If the tx has an unknown type of confidence, ignore.
if (!confidenceProto.hasType()) {
log.warn("Unknown confidence type for tx {}", tx.getHashAsString());
return;
}
ConfidenceType confidenceType =
TransactionConfidence.ConfidenceType.valueOf(confidenceProto.getType().getNumber());
confidence.setConfidenceType(confidenceType);
if (confidenceProto.hasAppearedAtHeight()) {
if (confidence.getConfidenceType() != ConfidenceType.BUILDING) {
log.warn("Have appearedAtHeight but not BUILDING for tx {}", tx.getHashAsString());
return;
}
confidence.setAppearedAtChainHeight(confidenceProto.getAppearedAtHeight());
}
if (confidenceProto.hasOverridingTransaction()) {
if (confidence.getConfidenceType() != ConfidenceType.OVERRIDDEN_BY_DOUBLE_SPEND) {
log.warn("Have overridingTransaction but not OVERRIDDEN for tx {}", tx.getHashAsString());
return;
}
Transaction overridingTransaction =
txMap.get(confidenceProto.getOverridingTransaction());
if (overridingTransaction == null) {
log.warn("Have overridingTransaction that is not in wallet for tx {}", tx.getHashAsString());
return;
}
confidence.setOverridingTransaction(overridingTransaction);
}
}
} }

View file

@ -11,19 +11,23 @@ public final class Protos {
public interface KeyOrBuilder public interface KeyOrBuilder
extends com.google.protobuf.MessageOrBuilder { extends com.google.protobuf.MessageOrBuilder {
// required bytes private_key = 1; // required .wallet.Key.Type type = 1;
boolean hasPrivateKey();
com.google.protobuf.ByteString getPrivateKey();
// required .wallet.Key.Type type = 2;
boolean hasType(); boolean hasType();
org.bitcoinj.wallet.Protos.Key.Type getType(); org.bitcoinj.wallet.Protos.Key.Type getType();
// optional string label = 3; // optional bytes private_key = 2;
boolean hasPrivateKey();
com.google.protobuf.ByteString getPrivateKey();
// optional bytes public_key = 3;
boolean hasPublicKey();
com.google.protobuf.ByteString getPublicKey();
// optional string label = 4;
boolean hasLabel(); boolean hasLabel();
String getLabel(); String getLabel();
// optional int64 creation_timestamp = 4; // optional int64 creation_timestamp = 5;
boolean hasCreationTimestamp(); boolean hasCreationTimestamp();
long getCreationTimestamp(); long getCreationTimestamp();
} }
@ -122,31 +126,41 @@ public final class Protos {
} }
private int bitField0_; private int bitField0_;
// required bytes private_key = 1; // required .wallet.Key.Type type = 1;
public static final int PRIVATE_KEY_FIELD_NUMBER = 1; public static final int TYPE_FIELD_NUMBER = 1;
private com.google.protobuf.ByteString privateKey_;
public boolean hasPrivateKey() {
return ((bitField0_ & 0x00000001) == 0x00000001);
}
public com.google.protobuf.ByteString getPrivateKey() {
return privateKey_;
}
// required .wallet.Key.Type type = 2;
public static final int TYPE_FIELD_NUMBER = 2;
private org.bitcoinj.wallet.Protos.Key.Type type_; private org.bitcoinj.wallet.Protos.Key.Type type_;
public boolean hasType() { public boolean hasType() {
return ((bitField0_ & 0x00000002) == 0x00000002); return ((bitField0_ & 0x00000001) == 0x00000001);
} }
public org.bitcoinj.wallet.Protos.Key.Type getType() { public org.bitcoinj.wallet.Protos.Key.Type getType() {
return type_; return type_;
} }
// optional string label = 3; // optional bytes private_key = 2;
public static final int LABEL_FIELD_NUMBER = 3; public static final int PRIVATE_KEY_FIELD_NUMBER = 2;
private com.google.protobuf.ByteString privateKey_;
public boolean hasPrivateKey() {
return ((bitField0_ & 0x00000002) == 0x00000002);
}
public com.google.protobuf.ByteString getPrivateKey() {
return privateKey_;
}
// optional bytes public_key = 3;
public static final int PUBLIC_KEY_FIELD_NUMBER = 3;
private com.google.protobuf.ByteString publicKey_;
public boolean hasPublicKey() {
return ((bitField0_ & 0x00000004) == 0x00000004);
}
public com.google.protobuf.ByteString getPublicKey() {
return publicKey_;
}
// optional string label = 4;
public static final int LABEL_FIELD_NUMBER = 4;
private java.lang.Object label_; private java.lang.Object label_;
public boolean hasLabel() { public boolean hasLabel() {
return ((bitField0_ & 0x00000004) == 0x00000004); return ((bitField0_ & 0x00000008) == 0x00000008);
} }
public String getLabel() { public String getLabel() {
java.lang.Object ref = label_; java.lang.Object ref = label_;
@ -174,19 +188,20 @@ public final class Protos {
} }
} }
// optional int64 creation_timestamp = 4; // optional int64 creation_timestamp = 5;
public static final int CREATION_TIMESTAMP_FIELD_NUMBER = 4; public static final int CREATION_TIMESTAMP_FIELD_NUMBER = 5;
private long creationTimestamp_; private long creationTimestamp_;
public boolean hasCreationTimestamp() { public boolean hasCreationTimestamp() {
return ((bitField0_ & 0x00000008) == 0x00000008); return ((bitField0_ & 0x00000010) == 0x00000010);
} }
public long getCreationTimestamp() { public long getCreationTimestamp() {
return creationTimestamp_; return creationTimestamp_;
} }
private void initFields() { private void initFields() {
privateKey_ = com.google.protobuf.ByteString.EMPTY;
type_ = org.bitcoinj.wallet.Protos.Key.Type.ORIGINAL; type_ = org.bitcoinj.wallet.Protos.Key.Type.ORIGINAL;
privateKey_ = com.google.protobuf.ByteString.EMPTY;
publicKey_ = com.google.protobuf.ByteString.EMPTY;
label_ = ""; label_ = "";
creationTimestamp_ = 0L; creationTimestamp_ = 0L;
} }
@ -195,10 +210,6 @@ public final class Protos {
byte isInitialized = memoizedIsInitialized; byte isInitialized = memoizedIsInitialized;
if (isInitialized != -1) return isInitialized == 1; if (isInitialized != -1) return isInitialized == 1;
if (!hasPrivateKey()) {
memoizedIsInitialized = 0;
return false;
}
if (!hasType()) { if (!hasType()) {
memoizedIsInitialized = 0; memoizedIsInitialized = 0;
return false; return false;
@ -211,16 +222,19 @@ public final class Protos {
throws java.io.IOException { throws java.io.IOException {
getSerializedSize(); getSerializedSize();
if (((bitField0_ & 0x00000001) == 0x00000001)) { if (((bitField0_ & 0x00000001) == 0x00000001)) {
output.writeBytes(1, privateKey_); output.writeEnum(1, type_.getNumber());
} }
if (((bitField0_ & 0x00000002) == 0x00000002)) { if (((bitField0_ & 0x00000002) == 0x00000002)) {
output.writeEnum(2, type_.getNumber()); output.writeBytes(2, privateKey_);
} }
if (((bitField0_ & 0x00000004) == 0x00000004)) { if (((bitField0_ & 0x00000004) == 0x00000004)) {
output.writeBytes(3, getLabelBytes()); output.writeBytes(3, publicKey_);
} }
if (((bitField0_ & 0x00000008) == 0x00000008)) { if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeInt64(4, creationTimestamp_); output.writeBytes(4, getLabelBytes());
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
output.writeInt64(5, creationTimestamp_);
} }
getUnknownFields().writeTo(output); getUnknownFields().writeTo(output);
} }
@ -233,19 +247,23 @@ public final class Protos {
size = 0; size = 0;
if (((bitField0_ & 0x00000001) == 0x00000001)) { if (((bitField0_ & 0x00000001) == 0x00000001)) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeBytesSize(1, privateKey_); .computeEnumSize(1, type_.getNumber());
} }
if (((bitField0_ & 0x00000002) == 0x00000002)) { if (((bitField0_ & 0x00000002) == 0x00000002)) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeEnumSize(2, type_.getNumber()); .computeBytesSize(2, privateKey_);
} }
if (((bitField0_ & 0x00000004) == 0x00000004)) { if (((bitField0_ & 0x00000004) == 0x00000004)) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeBytesSize(3, getLabelBytes()); .computeBytesSize(3, publicKey_);
} }
if (((bitField0_ & 0x00000008) == 0x00000008)) { if (((bitField0_ & 0x00000008) == 0x00000008)) {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeInt64Size(4, creationTimestamp_); .computeBytesSize(4, getLabelBytes());
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
size += com.google.protobuf.CodedOutputStream
.computeInt64Size(5, creationTimestamp_);
} }
size += getUnknownFields().getSerializedSize(); size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size; memoizedSerializedSize = size;
@ -371,14 +389,16 @@ public final class Protos {
public Builder clear() { public Builder clear() {
super.clear(); super.clear();
privateKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000001);
type_ = org.bitcoinj.wallet.Protos.Key.Type.ORIGINAL; type_ = org.bitcoinj.wallet.Protos.Key.Type.ORIGINAL;
bitField0_ = (bitField0_ & ~0x00000001);
privateKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000002); bitField0_ = (bitField0_ & ~0x00000002);
label_ = ""; publicKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000004); bitField0_ = (bitField0_ & ~0x00000004);
creationTimestamp_ = 0L; label_ = "";
bitField0_ = (bitField0_ & ~0x00000008); bitField0_ = (bitField0_ & ~0x00000008);
creationTimestamp_ = 0L;
bitField0_ = (bitField0_ & ~0x00000010);
return this; return this;
} }
@ -420,18 +440,22 @@ public final class Protos {
if (((from_bitField0_ & 0x00000001) == 0x00000001)) { if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
to_bitField0_ |= 0x00000001; to_bitField0_ |= 0x00000001;
} }
result.privateKey_ = privateKey_; result.type_ = type_;
if (((from_bitField0_ & 0x00000002) == 0x00000002)) { if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
to_bitField0_ |= 0x00000002; to_bitField0_ |= 0x00000002;
} }
result.type_ = type_; result.privateKey_ = privateKey_;
if (((from_bitField0_ & 0x00000004) == 0x00000004)) { if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
to_bitField0_ |= 0x00000004; to_bitField0_ |= 0x00000004;
} }
result.label_ = label_; result.publicKey_ = publicKey_;
if (((from_bitField0_ & 0x00000008) == 0x00000008)) { if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
to_bitField0_ |= 0x00000008; to_bitField0_ |= 0x00000008;
} }
result.label_ = label_;
if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
to_bitField0_ |= 0x00000010;
}
result.creationTimestamp_ = creationTimestamp_; result.creationTimestamp_ = creationTimestamp_;
result.bitField0_ = to_bitField0_; result.bitField0_ = to_bitField0_;
onBuilt(); onBuilt();
@ -449,11 +473,14 @@ public final class Protos {
public Builder mergeFrom(org.bitcoinj.wallet.Protos.Key other) { public Builder mergeFrom(org.bitcoinj.wallet.Protos.Key other) {
if (other == org.bitcoinj.wallet.Protos.Key.getDefaultInstance()) return this; if (other == org.bitcoinj.wallet.Protos.Key.getDefaultInstance()) return this;
if (other.hasType()) {
setType(other.getType());
}
if (other.hasPrivateKey()) { if (other.hasPrivateKey()) {
setPrivateKey(other.getPrivateKey()); setPrivateKey(other.getPrivateKey());
} }
if (other.hasType()) { if (other.hasPublicKey()) {
setType(other.getType()); setPublicKey(other.getPublicKey());
} }
if (other.hasLabel()) { if (other.hasLabel()) {
setLabel(other.getLabel()); setLabel(other.getLabel());
@ -466,10 +493,6 @@ public final class Protos {
} }
public final boolean isInitialized() { public final boolean isInitialized() {
if (!hasPrivateKey()) {
return false;
}
if (!hasType()) { if (!hasType()) {
return false; return false;
@ -500,29 +523,34 @@ public final class Protos {
} }
break; break;
} }
case 10: { case 8: {
bitField0_ |= 0x00000001;
privateKey_ = input.readBytes();
break;
}
case 16: {
int rawValue = input.readEnum(); int rawValue = input.readEnum();
org.bitcoinj.wallet.Protos.Key.Type value = org.bitcoinj.wallet.Protos.Key.Type.valueOf(rawValue); org.bitcoinj.wallet.Protos.Key.Type value = org.bitcoinj.wallet.Protos.Key.Type.valueOf(rawValue);
if (value == null) { if (value == null) {
unknownFields.mergeVarintField(2, rawValue); unknownFields.mergeVarintField(1, rawValue);
} else { } else {
bitField0_ |= 0x00000002; bitField0_ |= 0x00000001;
type_ = value; type_ = value;
} }
break; break;
} }
case 18: {
bitField0_ |= 0x00000002;
privateKey_ = input.readBytes();
break;
}
case 26: { case 26: {
bitField0_ |= 0x00000004; bitField0_ |= 0x00000004;
publicKey_ = input.readBytes();
break;
}
case 34: {
bitField0_ |= 0x00000008;
label_ = input.readBytes(); label_ = input.readBytes();
break; break;
} }
case 32: { case 40: {
bitField0_ |= 0x00000008; bitField0_ |= 0x00000010;
creationTimestamp_ = input.readInt64(); creationTimestamp_ = input.readInt64();
break; break;
} }
@ -532,34 +560,10 @@ public final class Protos {
private int bitField0_; private int bitField0_;
// required bytes private_key = 1; // required .wallet.Key.Type type = 1;
private com.google.protobuf.ByteString privateKey_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasPrivateKey() {
return ((bitField0_ & 0x00000001) == 0x00000001);
}
public com.google.protobuf.ByteString getPrivateKey() {
return privateKey_;
}
public Builder setPrivateKey(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000001;
privateKey_ = value;
onChanged();
return this;
}
public Builder clearPrivateKey() {
bitField0_ = (bitField0_ & ~0x00000001);
privateKey_ = getDefaultInstance().getPrivateKey();
onChanged();
return this;
}
// required .wallet.Key.Type type = 2;
private org.bitcoinj.wallet.Protos.Key.Type type_ = org.bitcoinj.wallet.Protos.Key.Type.ORIGINAL; private org.bitcoinj.wallet.Protos.Key.Type type_ = org.bitcoinj.wallet.Protos.Key.Type.ORIGINAL;
public boolean hasType() { public boolean hasType() {
return ((bitField0_ & 0x00000002) == 0x00000002); return ((bitField0_ & 0x00000001) == 0x00000001);
} }
public org.bitcoinj.wallet.Protos.Key.Type getType() { public org.bitcoinj.wallet.Protos.Key.Type getType() {
return type_; return type_;
@ -568,22 +572,70 @@ public final class Protos {
if (value == null) { if (value == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
bitField0_ |= 0x00000002; bitField0_ |= 0x00000001;
type_ = value; type_ = value;
onChanged(); onChanged();
return this; return this;
} }
public Builder clearType() { public Builder clearType() {
bitField0_ = (bitField0_ & ~0x00000002); bitField0_ = (bitField0_ & ~0x00000001);
type_ = org.bitcoinj.wallet.Protos.Key.Type.ORIGINAL; type_ = org.bitcoinj.wallet.Protos.Key.Type.ORIGINAL;
onChanged(); onChanged();
return this; return this;
} }
// optional string label = 3; // optional bytes private_key = 2;
private com.google.protobuf.ByteString privateKey_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasPrivateKey() {
return ((bitField0_ & 0x00000002) == 0x00000002);
}
public com.google.protobuf.ByteString getPrivateKey() {
return privateKey_;
}
public Builder setPrivateKey(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000002;
privateKey_ = value;
onChanged();
return this;
}
public Builder clearPrivateKey() {
bitField0_ = (bitField0_ & ~0x00000002);
privateKey_ = getDefaultInstance().getPrivateKey();
onChanged();
return this;
}
// optional bytes public_key = 3;
private com.google.protobuf.ByteString publicKey_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasPublicKey() {
return ((bitField0_ & 0x00000004) == 0x00000004);
}
public com.google.protobuf.ByteString getPublicKey() {
return publicKey_;
}
public Builder setPublicKey(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000004;
publicKey_ = value;
onChanged();
return this;
}
public Builder clearPublicKey() {
bitField0_ = (bitField0_ & ~0x00000004);
publicKey_ = getDefaultInstance().getPublicKey();
onChanged();
return this;
}
// optional string label = 4;
private java.lang.Object label_ = ""; private java.lang.Object label_ = "";
public boolean hasLabel() { public boolean hasLabel() {
return ((bitField0_ & 0x00000004) == 0x00000004); return ((bitField0_ & 0x00000008) == 0x00000008);
} }
public String getLabel() { public String getLabel() {
java.lang.Object ref = label_; java.lang.Object ref = label_;
@ -599,39 +651,39 @@ public final class Protos {
if (value == null) { if (value == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
bitField0_ |= 0x00000004; bitField0_ |= 0x00000008;
label_ = value; label_ = value;
onChanged(); onChanged();
return this; return this;
} }
public Builder clearLabel() { public Builder clearLabel() {
bitField0_ = (bitField0_ & ~0x00000004); bitField0_ = (bitField0_ & ~0x00000008);
label_ = getDefaultInstance().getLabel(); label_ = getDefaultInstance().getLabel();
onChanged(); onChanged();
return this; return this;
} }
void setLabel(com.google.protobuf.ByteString value) { void setLabel(com.google.protobuf.ByteString value) {
bitField0_ |= 0x00000004; bitField0_ |= 0x00000008;
label_ = value; label_ = value;
onChanged(); onChanged();
} }
// optional int64 creation_timestamp = 4; // optional int64 creation_timestamp = 5;
private long creationTimestamp_ ; private long creationTimestamp_ ;
public boolean hasCreationTimestamp() { public boolean hasCreationTimestamp() {
return ((bitField0_ & 0x00000008) == 0x00000008); return ((bitField0_ & 0x00000010) == 0x00000010);
} }
public long getCreationTimestamp() { public long getCreationTimestamp() {
return creationTimestamp_; return creationTimestamp_;
} }
public Builder setCreationTimestamp(long value) { public Builder setCreationTimestamp(long value) {
bitField0_ |= 0x00000008; bitField0_ |= 0x00000010;
creationTimestamp_ = value; creationTimestamp_ = value;
onChanged(); onChanged();
return this; return this;
} }
public Builder clearCreationTimestamp() { public Builder clearCreationTimestamp() {
bitField0_ = (bitField0_ & ~0x00000008); bitField0_ = (bitField0_ & ~0x00000010);
creationTimestamp_ = 0L; creationTimestamp_ = 0L;
onChanged(); onChanged();
return this; return this;
@ -1721,7 +1773,7 @@ public final class Protos {
public interface TransactionConfidenceOrBuilder public interface TransactionConfidenceOrBuilder
extends com.google.protobuf.MessageOrBuilder { extends com.google.protobuf.MessageOrBuilder {
// required .wallet.TransactionConfidence.Type type = 1; // optional .wallet.TransactionConfidence.Type type = 1;
boolean hasType(); boolean hasType();
org.bitcoinj.wallet.Protos.TransactionConfidence.Type getType(); org.bitcoinj.wallet.Protos.TransactionConfidence.Type getType();
@ -1840,7 +1892,7 @@ public final class Protos {
} }
private int bitField0_; private int bitField0_;
// required .wallet.TransactionConfidence.Type type = 1; // optional .wallet.TransactionConfidence.Type type = 1;
public static final int TYPE_FIELD_NUMBER = 1; public static final int TYPE_FIELD_NUMBER = 1;
private org.bitcoinj.wallet.Protos.TransactionConfidence.Type type_; private org.bitcoinj.wallet.Protos.TransactionConfidence.Type type_;
public boolean hasType() { public boolean hasType() {
@ -1880,10 +1932,6 @@ public final class Protos {
byte isInitialized = memoizedIsInitialized; byte isInitialized = memoizedIsInitialized;
if (isInitialized != -1) return isInitialized == 1; if (isInitialized != -1) return isInitialized == 1;
if (!hasType()) {
memoizedIsInitialized = 0;
return false;
}
memoizedIsInitialized = 1; memoizedIsInitialized = 1;
return true; return true;
} }
@ -2131,10 +2179,6 @@ public final class Protos {
} }
public final boolean isInitialized() { public final boolean isInitialized() {
if (!hasType()) {
return false;
}
return true; return true;
} }
@ -2188,7 +2232,7 @@ public final class Protos {
private int bitField0_; private int bitField0_;
// required .wallet.TransactionConfidence.Type type = 1; // optional .wallet.TransactionConfidence.Type type = 1;
private org.bitcoinj.wallet.Protos.TransactionConfidence.Type type_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Type.UNKNOWN; private org.bitcoinj.wallet.Protos.TransactionConfidence.Type type_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Type.UNKNOWN;
public boolean hasType() { public boolean hasType() {
return ((bitField0_ & 0x00000001) == 0x00000001); return ((bitField0_ & 0x00000001) == 0x00000001);
@ -2590,12 +2634,6 @@ public final class Protos {
return false; return false;
} }
} }
if (hasConfidence()) {
if (!getConfidence().isInitialized()) {
memoizedIsInitialized = 0;
return false;
}
}
memoizedIsInitialized = 1; memoizedIsInitialized = 1;
return true; return true;
} }
@ -3051,12 +3089,6 @@ public final class Protos {
return false; return false;
} }
} }
if (hasConfidence()) {
if (!getConfidence().isInitialized()) {
return false;
}
}
return true; return true;
} }
@ -5639,39 +5671,40 @@ public final class Protos {
descriptor; descriptor;
static { static {
java.lang.String[] descriptorData = { java.lang.String[] descriptorData = {
"\n\rbitcoin.proto\022\006wallet\"{\n\003Key\022\023\n\013privat" + "\n\rbitcoin.proto\022\006wallet\"\217\001\n\003Key\022\036\n\004type\030" +
"e_key\030\001 \002(\014\022\036\n\004type\030\002 \002(\0162\020.wallet.Key.T" + "\001 \002(\0162\020.wallet.Key.Type\022\023\n\013private_key\030\002" +
"ype\022\r\n\005label\030\003 \001(\t\022\032\n\022creation_timestamp" + " \001(\014\022\022\n\npublic_key\030\003 \001(\014\022\r\n\005label\030\004 \001(\t\022" +
"\030\004 \001(\003\"\024\n\004Type\022\014\n\010ORIGINAL\020\001\"\203\001\n\020Transac" + "\032\n\022creation_timestamp\030\005 \001(\003\"\024\n\004Type\022\014\n\010O" +
"tionInput\022\"\n\032transaction_out_point_hash\030" + "RIGINAL\020\001\"\203\001\n\020TransactionInput\022\"\n\032transa" +
"\001 \002(\014\022#\n\033transaction_out_point_index\030\002 \002" + "ction_out_point_hash\030\001 \002(\014\022#\n\033transactio" +
"(\005\022\024\n\014script_bytes\030\003 \002(\014\022\020\n\010sequence\030\004 \001" + "n_out_point_index\030\002 \002(\005\022\024\n\014script_bytes\030" +
"(\r\"\177\n\021TransactionOutput\022\r\n\005value\030\001 \002(\003\022\024" + "\003 \002(\014\022\020\n\010sequence\030\004 \001(\r\"\177\n\021TransactionOu" +
"\n\014script_bytes\030\002 \002(\014\022!\n\031spent_by_transac" + "tput\022\r\n\005value\030\001 \002(\003\022\024\n\014script_bytes\030\002 \002(" +
"tion_hash\030\003 \001(\014\022\"\n\032spent_by_transaction_", "\014\022!\n\031spent_by_transaction_hash\030\003 \001(\014\022\"\n\032",
"index\030\004 \001(\005\"\366\001\n\025TransactionConfidence\0220\n" + "spent_by_transaction_index\030\004 \001(\005\"\366\001\n\025Tra" +
"\004type\030\001 \002(\0162\".wallet.TransactionConfiden" + "nsactionConfidence\0220\n\004type\030\001 \001(\0162\".walle" +
"ce.Type\022\032\n\022appeared_at_height\030\002 \001(\005\022\036\n\026o" + "t.TransactionConfidence.Type\022\032\n\022appeared" +
"verriding_transaction\030\003 \001(\014\"o\n\004Type\022\013\n\007U" + "_at_height\030\002 \001(\005\022\036\n\026overriding_transacti" +
"NKNOWN\020\000\022\014\n\010BUILDING\020\001\022\025\n\021NOT_SEEN_IN_CH" + "on\030\003 \001(\014\"o\n\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDIN" +
"AIN\020\002\022\025\n\021NOT_IN_BEST_CHAIN\020\003\022\036\n\032OVERRIDD" + "G\020\001\022\025\n\021NOT_SEEN_IN_CHAIN\020\002\022\025\n\021NOT_IN_BES" +
"EN_BY_DOUBLE_SPEND\020\004\"\211\003\n\013Transaction\022\017\n\007" + "T_CHAIN\020\003\022\036\n\032OVERRIDDEN_BY_DOUBLE_SPEND\020" +
"version\030\001 \002(\005\022\014\n\004hash\030\002 \002(\014\022&\n\004pool\030\003 \002(" + "\004\"\211\003\n\013Transaction\022\017\n\007version\030\001 \002(\005\022\014\n\004ha" +
"\0162\030.wallet.Transaction.Pool\022\021\n\tlock_time" + "sh\030\002 \002(\014\022&\n\004pool\030\003 \002(\0162\030.wallet.Transact" +
"\030\004 \001(\r\022\022\n\nupdated_at\030\005 \001(\003\0223\n\021transactio", "ion.Pool\022\021\n\tlock_time\030\004 \001(\r\022\022\n\nupdated_a",
"n_input\030\006 \003(\0132\030.wallet.TransactionInput\022" + "t\030\005 \001(\003\0223\n\021transaction_input\030\006 \003(\0132\030.wal" +
"5\n\022transaction_output\030\007 \003(\0132\031.wallet.Tra" + "let.TransactionInput\0225\n\022transaction_outp" +
"nsactionOutput\022\022\n\nblock_hash\030\010 \003(\014\0221\n\nco" + "ut\030\007 \003(\0132\031.wallet.TransactionOutput\022\022\n\nb" +
"nfidence\030\t \001(\0132\035.wallet.TransactionConfi" + "lock_hash\030\010 \003(\014\0221\n\nconfidence\030\t \001(\0132\035.wa" +
"dence\"Y\n\004Pool\022\013\n\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n" + "llet.TransactionConfidence\"Y\n\004Pool\022\013\n\007UN" +
"\010INACTIVE\020\002\022\010\n\004DEAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PE" + "SPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004DEAD" +
"NDING_INACTIVE\020\022\"8\n\tExtension\022\n\n\002id\030\001 \002(" + "\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022\"8\n" +
"\t\022\014\n\004data\030\002 \002(\014\022\021\n\tmandatory\030\003 \002(\010\"\254\001\n\006W" + "\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022\021\n\t" +
"allet\022\032\n\022network_identifier\030\001 \002(\t\022\034\n\024las" + "mandatory\030\003 \002(\010\"\254\001\n\006Wallet\022\032\n\022network_id" +
"t_seen_block_hash\030\002 \001(\014\022\030\n\003key\030\003 \003(\0132\013.w", "entifier\030\001 \002(\t\022\034\n\024last_seen_block_hash\030\002",
"allet.Key\022(\n\013transaction\030\004 \003(\0132\023.wallet." + " \001(\014\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013transa" +
"Transaction\022$\n\textension\030\n \003(\0132\021.wallet." + "ction\030\004 \003(\0132\023.wallet.Transaction\022$\n\texte" +
"ExtensionB\035\n\023org.bitcoinj.walletB\006Protos" "nsion\030\n \003(\0132\021.wallet.ExtensionB\035\n\023org.bi" +
"tcoinj.walletB\006Protos"
}; };
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@ -5683,7 +5716,7 @@ public final class Protos {
internal_static_wallet_Key_fieldAccessorTable = new internal_static_wallet_Key_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable( com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Key_descriptor, internal_static_wallet_Key_descriptor,
new java.lang.String[] { "PrivateKey", "Type", "Label", "CreationTimestamp", }, new java.lang.String[] { "Type", "PrivateKey", "PublicKey", "Label", "CreationTimestamp", },
org.bitcoinj.wallet.Protos.Key.class, org.bitcoinj.wallet.Protos.Key.class,
org.bitcoinj.wallet.Protos.Key.Builder.class); org.bitcoinj.wallet.Protos.Key.Builder.class);
internal_static_wallet_TransactionInput_descriptor = internal_static_wallet_TransactionInput_descriptor =

View file

@ -31,7 +31,7 @@ public class ECKeyTest {
// Test that we can construct an ECKey from a private key (deriving the public from the private), then signing // Test that we can construct an ECKey from a private key (deriving the public from the private), then signing
// a message with it. // a message with it.
BigInteger privkey = new BigInteger(1, Hex.decode("180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19")); BigInteger privkey = new BigInteger(1, Hex.decode("180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"));
ECKey key = new ECKey(privkey, null); ECKey key = new ECKey(privkey);
byte[] message = new byte[32]; // All zeroes. byte[] message = new byte[32]; // All zeroes.
byte[] output = key.sign(message); byte[] output = key.sign(message);
assertTrue(key.verify(message, output)); assertTrue(key.verify(message, output));
@ -70,6 +70,35 @@ public class ECKeyTest {
assertTrue(decodedKey.verify(message, roundtripKey.sign(message))); assertTrue(decodedKey.verify(message, roundtripKey.sign(message)));
} }
@Test
public void testKeyPairRoundtrip() {
byte[] privkeyASN1 = Hex.decode(
"3082011302010104205c0b98e524ad188ddef35dc6abba13c34a351a05409e5d285403718b93336a4aa081a53081a2020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101a144034200042af7a2aafe8dafd7dc7f9cfb58ce09bda7dce28653ab229b98d1d3d759660c672dd0db18c8c2d76aa470448e876fc2089ab1354c01a6e72cefc50915f4a963ee");
ECKey decodedKey = ECKey.fromASN1(privkeyASN1);
// Now re-encode and decode the ASN.1 to see if it is equivalent (it does not produce the exact same byte
// sequence, some integers are padded now).
ECKey roundtripKey =
new ECKey(decodedKey.getPrivKeyBytes(), decodedKey.getPubKey());
for (ECKey key : new ECKey[] {decodedKey, roundtripKey}) {
byte[] message = reverseBytes(Hex.decode(
"11da3761e86431e4a54c176789e41f1651b324d240d599a7067bee23d328ec2a"));
byte[] output = key.sign(message);
assertTrue(key.verify(message, output));
output = Hex.decode(
"304502206faa2ebc614bf4a0b31f0ce4ed9012eb193302ec2bcaccc7ae8bb40577f47549022100c73a1a1acc209f3f860bf9b9f5e13e9433db6f8b7bd527a088a0e0cd0a4c83e9");
assertTrue(key.verify(message, output));
}
// Try to sign with one key and verify with the other.
byte[] message = reverseBytes(Hex.decode(
"11da3761e86431e4a54c176789e41f1651b324d240d599a7067bee23d328ec2a"));
assertTrue(roundtripKey.verify(message, decodedKey.sign(message)));
assertTrue(decodedKey.verify(message, roundtripKey.sign(message)));
}
@Test @Test
public void base58Encoding() throws Exception { public void base58Encoding() throws Exception {
String addr = "mqAJmaxMcG5pPHHc3H3NtyXzY7kGbJLuMF"; String addr = "mqAJmaxMcG5pPHHc3H3NtyXzY7kGbJLuMF";