();
@@ -72,7 +90,6 @@ public class WalletProtobufSerializer {
this.helper = h;
}
-
/**
* Formats the given wallet (transactions and keys) to the given output stream in protocol buffer format.
*
@@ -102,39 +119,86 @@ public class WalletProtobufSerializer {
public Protos.Wallet walletToProto(Wallet wallet) {
Protos.Wallet.Builder walletBuilder = Protos.Wallet.newBuilder();
walletBuilder.setNetworkIdentifier(wallet.getNetworkParameters().getId());
+ if (wallet.getDescription() != null) {
+ walletBuilder.setDescription(wallet.getDescription());
+ }
+
for (WalletTransaction wtx : wallet.getWalletTransactions()) {
Protos.Transaction txProto = makeTxProto(wtx);
walletBuilder.addTransaction(txProto);
}
-
+
for (ECKey key : wallet.getKeys()) {
- Protos.Key.Builder buf = Protos.Key.newBuilder().setCreationTimestamp(key.getCreationTimeSeconds() * 1000)
+ Protos.Key.Builder keyBuilder = Protos.Key.newBuilder().setCreationTimestamp(key.getCreationTimeSeconds() * 1000)
// .setLabel() TODO
.setType(Protos.Key.Type.ORIGINAL);
if (key.getPrivKeyBytes() != null)
- buf.setPrivateKey(ByteString.copyFrom(key.getPrivKeyBytes()));
+ keyBuilder.setPrivateKey(ByteString.copyFrom(key.getPrivKeyBytes()));
+
+ EncryptedPrivateKey encryptedPrivateKey = key.getEncryptedPrivateKey();
+ if (encryptedPrivateKey != null) {
+ // Key is encrypted.
+ Protos.EncryptedPrivateKey.Builder encryptedKeyBuilder = Protos.EncryptedPrivateKey.newBuilder()
+ .setEncryptedPrivateKey(ByteString.copyFrom(encryptedPrivateKey.getEncryptedBytes()))
+ .setInitialisationVector(ByteString.copyFrom(encryptedPrivateKey.getInitialisationVector()));
+
+ if (key.getKeyCrypter() == null) {
+ throw new IllegalStateException("The encrypted key " + key.toString() + " has no KeyCrypter.");
+ } else {
+ // If it is a Scrypt + AES encrypted key, set the persisted key type.
+ if (key.getKeyCrypter().getUnderstoodEncryptionType() == Protos.Wallet.EncryptionType.ENCRYPTED_SCRYPT_AES) {
+ keyBuilder.setType(Protos.Key.Type.ENCRYPTED_SCRYPT_AES);
+ } else {
+ throw new IllegalArgumentException("The key " + key.toString() + " is encrypted with a KeyCrypter of type " + key.getKeyCrypter().getUnderstoodEncryptionType() +
+ ". This WalletProtobufSerialiser does not understand that type of encryption.");
+ }
+ }
+ keyBuilder.setEncryptedPrivateKey(encryptedKeyBuilder);
+ }
+
// We serialize the public key even if the private key is present for speed reasons: we don't want to do
// lots of slow EC math to load the wallet, we prefer to store the redundant data instead. It matters more
// on mobile platforms.
- buf.setPublicKey(ByteString.copyFrom(key.getPubKey()));
- walletBuilder.addKey(buf);
+ keyBuilder.setPublicKey(ByteString.copyFrom(key.getPubKey()));
+ walletBuilder.addKey(keyBuilder);
}
+ // Populate the lastSeenBlockHash field.
Sha256Hash lastSeenBlockHash = wallet.getLastBlockSeenHash();
if (lastSeenBlockHash != null) {
walletBuilder.setLastSeenBlockHash(hashToByteString(lastSeenBlockHash));
walletBuilder.setLastSeenBlockHeight(wallet.getLastBlockSeenHeight());
}
+ // Populate the scrypt parameters.
+ KeyCrypter keyCrypter = wallet.getKeyCrypter();
+ if (keyCrypter == null) {
+ // The wallet is unencrypted.
+ walletBuilder.setEncryptionType(EncryptionType.UNENCRYPTED);
+ } else {
+ // The wallet is encrypted.
+ walletBuilder.setEncryptionType(keyCrypter.getUnderstoodEncryptionType());
+ if (keyCrypter instanceof KeyCrypterScrypt) {
+ KeyCrypterScrypt keyCrypterScrypt = (KeyCrypterScrypt) keyCrypter;
+ walletBuilder.setEncryptionParameters(keyCrypterScrypt.getScryptParameters());
+ } else {
+ // Some other form of encryption has been specified that we do not know how to persist.
+ throw new RuntimeException("The wallet has encryption of type '" + keyCrypter.getUnderstoodEncryptionType() + "' but this WalletProtobufSerializer does not know how to persist this.");
+ }
+ }
+
+ // Populate the wallet version.
+ walletBuilder.setVersion(wallet.getVersion());
+
Collection extensions = helper.getExtensionsToWrite(wallet);
for(Protos.Extension ext : extensions) {
walletBuilder.addExtension(ext);
}
-
+
return walletBuilder.build();
}
- private static Protos.Transaction makeTxProto(WalletTransaction wtx) {
+ protected static Protos.Transaction makeTxProto(WalletTransaction wtx) {
Transaction tx = wtx.getTransaction();
Protos.Transaction.Builder txBuilder = Protos.Transaction.newBuilder();
@@ -193,7 +257,7 @@ public class WalletProtobufSerializer {
return txBuilder.build();
}
- private static void writeConfidence(Protos.Transaction.Builder txBuilder,
+ protected static void writeConfidence(Protos.Transaction.Builder txBuilder,
TransactionConfidence confidence,
Protos.TransactionConfidence.Builder confidenceBuilder) {
synchronized (confidence) {
@@ -206,8 +270,12 @@ public class WalletProtobufSerializer {
}
}
if (confidence.getConfidenceType() == ConfidenceType.DEAD) {
- Sha256Hash overridingHash = confidence.getOverridingTransaction().getHash();
- confidenceBuilder.setOverridingTransaction(hashToByteString(overridingHash));
+ // Copy in the overriding transaction, if available.
+ // (A dead coinbase transaction has no overriding transaction).
+ if (confidence.getOverridingTransaction() != null) {
+ Sha256Hash overridingHash = confidence.getOverridingTransaction().getHash();
+ confidenceBuilder.setOverridingTransaction(hashToByteString(overridingHash));
+ }
}
TransactionConfidence.Source source = confidence.getSource();
switch (source) {
@@ -219,6 +287,7 @@ public class WalletProtobufSerializer {
confidenceBuilder.setSource(Protos.TransactionConfidence.Source.SOURCE_UNKNOWN); break;
}
}
+
for (ListIterator it = confidence.getBroadcastBy(); it.hasNext();) {
PeerAddress address = it.next();
Protos.PeerAddress proto = Protos.PeerAddress.newBuilder()
@@ -231,11 +300,11 @@ public class WalletProtobufSerializer {
txBuilder.setConfidence(confidenceBuilder);
}
- private static ByteString hashToByteString(Sha256Hash hash) {
+ public static ByteString hashToByteString(Sha256Hash hash) {
return ByteString.copyFrom(hash.getBytes());
}
- private static Sha256Hash byteStringToHash(ByteString bs) {
+ public static Sha256Hash byteStringToHash(ByteString bs) {
return new Sha256Hash(bs.toByteArray());
}
@@ -245,7 +314,6 @@ public class WalletProtobufSerializer {
*
* If the stream is invalid or the serialized wallet contains unsupported features,
* {@link IllegalArgumentException} is thrown.
- *
*/
public Wallet readWallet(InputStream input) throws IOException {
// TODO: This method should throw more specific exception types than IllegalArgumentException.
@@ -253,24 +321,48 @@ public class WalletProtobufSerializer {
// System.out.println(TextFormat.printToString(walletProto));
+ // Read the scrypt parameters that specify how encryption and decryption is performed.
+ KeyCrypter keyCrypter = null;
+ if (walletProto.hasEncryptionParameters()) {
+ Protos.ScryptParameters encryptionParameters = walletProto.getEncryptionParameters();
+ keyCrypter = new KeyCrypterScrypt(encryptionParameters);
+ }
+
NetworkParameters params = NetworkParameters.fromID(walletProto.getNetworkIdentifier());
- Wallet wallet = helper.newWallet(params);
-
+ Wallet wallet = helper.newWallet(params, keyCrypter);
+
+ if (walletProto.hasDescription()) {
+ wallet.setDescription(walletProto.getDescription());
+ }
+
// Read all keys
for (Protos.Key keyProto : walletProto.getKeyList()) {
- if (keyProto.getType() != Protos.Key.Type.ORIGINAL) {
- throw new IllegalArgumentException("Unknown key type in wallet");
+ if (!(keyProto.getType() == Protos.Key.Type.ORIGINAL || keyProto.getType() == Protos.Key.Type.ENCRYPTED_SCRYPT_AES)) {
+ throw new IllegalArgumentException("Unknown key type in wallet, type = " + keyProto.getType());
}
- byte[] privKey = null;
- if (keyProto.hasPrivateKey()) {
- privKey = keyProto.getPrivateKey().toByteArray();
+
+ byte[] privKey = keyProto.hasPrivateKey() ? keyProto.getPrivateKey().toByteArray() : null;
+ EncryptedPrivateKey encryptedPrivateKey = null;
+ if (keyProto.hasEncryptedPrivateKey()) {
+ Protos.EncryptedPrivateKey encryptedPrivateKeyProto = keyProto.getEncryptedPrivateKey();
+ encryptedPrivateKey = new EncryptedPrivateKey(encryptedPrivateKeyProto.getInitialisationVector().toByteArray(),
+ encryptedPrivateKeyProto.getEncryptedPrivateKey().toByteArray());
}
+
byte[] pubKey = keyProto.hasPublicKey() ? keyProto.getPublicKey().toByteArray() : null;
- ECKey ecKey = new ECKey(privKey, pubKey);
+
+ ECKey ecKey = null;
+ if (keyCrypter != null && keyCrypter.getUnderstoodEncryptionType() != EncryptionType.UNENCRYPTED) {
+ // If the key is encrypted construct an ECKey using the encrypted private key bytes.
+ ecKey = new ECKey(encryptedPrivateKey, pubKey, keyCrypter);
+ } else {
+ // Construct an unencrypted private key.
+ ecKey = new ECKey(privKey, pubKey);
+ }
ecKey.setCreationTimeSeconds((keyProto.getCreationTimestamp() + 500) / 1000);
wallet.addKey(ecKey);
}
-
+
// Read all transactions and insert into the txMap.
for (Protos.Transaction txProto : walletProto.getTransactionList()) {
readTransaction(txProto, params);
@@ -281,7 +373,7 @@ public class WalletProtobufSerializer {
WalletTransaction wtx = connectTransactionOutputs(txProto);
wallet.addWalletTransaction(wtx);
}
-
+
// Update the lastBlockSeenHash.
if (!walletProto.hasLastSeenBlockHash()) {
wallet.setLastBlockSeenHash(null);
@@ -297,7 +389,11 @@ public class WalletProtobufSerializer {
for (Protos.Extension extProto : walletProto.getExtensionList()) {
helper.readExtension(wallet, extProto);
}
-
+
+ if (walletProto.hasVersion()) {
+ wallet.setVersion(walletProto.getVersion());
+ }
+
return wallet;
}
@@ -310,7 +406,7 @@ public class WalletProtobufSerializer {
return Protos.Wallet.parseFrom(input);
}
- private void readTransaction(Protos.Transaction txProto, NetworkParameters params) {
+ protected void readTransaction(Protos.Transaction txProto, NetworkParameters params) {
Transaction tx = new Transaction(params);
if (txProto.hasUpdatedAt()) {
tx.setUpdateTime(new Date(txProto.getUpdatedAt()));
@@ -353,7 +449,7 @@ public class WalletProtobufSerializer {
txMap.put(txProto.getHash(), tx);
}
- private WalletTransaction connectTransactionOutputs(org.bitcoinj.wallet.Protos.Transaction txProto) {
+ protected WalletTransaction connectTransactionOutputs(org.bitcoinj.wallet.Protos.Transaction txProto) {
Transaction tx = txMap.get(txProto.getHash());
WalletTransaction.Pool pool = WalletTransaction.Pool.valueOf(txProto.getPool().getNumber());
for (int i = 0 ; i < tx.getOutputs().size() ; i++) {
@@ -376,7 +472,7 @@ public class WalletProtobufSerializer {
return new WalletTransaction(pool, tx);
}
- private void readConfidence(Transaction tx, Protos.TransactionConfidence confidenceProto,
+ protected 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.
diff --git a/core/src/main/java/org/bitcoinj/wallet/Protos.java b/core/src/main/java/org/bitcoinj/wallet/Protos.java
index 78ae82b9..0804fec0 100644
--- a/core/src/main/java/org/bitcoinj/wallet/Protos.java
+++ b/core/src/main/java/org/bitcoinj/wallet/Protos.java
@@ -487,6 +487,423 @@ public final class Protos {
// @@protoc_insertion_point(class_scope:wallet.PeerAddress)
}
+ public interface EncryptedPrivateKeyOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // required bytes initialisation_vector = 1;
+ boolean hasInitialisationVector();
+ com.google.protobuf.ByteString getInitialisationVector();
+
+ // required bytes encrypted_private_key = 2;
+ boolean hasEncryptedPrivateKey();
+ com.google.protobuf.ByteString getEncryptedPrivateKey();
+ }
+ public static final class EncryptedPrivateKey extends
+ com.google.protobuf.GeneratedMessage
+ implements EncryptedPrivateKeyOrBuilder {
+ // Use EncryptedPrivateKey.newBuilder() to construct.
+ private EncryptedPrivateKey(Builder builder) {
+ super(builder);
+ }
+ private EncryptedPrivateKey(boolean noInit) {}
+
+ private static final EncryptedPrivateKey defaultInstance;
+ public static EncryptedPrivateKey getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public EncryptedPrivateKey getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.bitcoinj.wallet.Protos.internal_static_wallet_EncryptedPrivateKey_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.bitcoinj.wallet.Protos.internal_static_wallet_EncryptedPrivateKey_fieldAccessorTable;
+ }
+
+ private int bitField0_;
+ // required bytes initialisation_vector = 1;
+ public static final int INITIALISATION_VECTOR_FIELD_NUMBER = 1;
+ private com.google.protobuf.ByteString initialisationVector_;
+ public boolean hasInitialisationVector() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public com.google.protobuf.ByteString getInitialisationVector() {
+ return initialisationVector_;
+ }
+
+ // required bytes encrypted_private_key = 2;
+ public static final int ENCRYPTED_PRIVATE_KEY_FIELD_NUMBER = 2;
+ private com.google.protobuf.ByteString encryptedPrivateKey_;
+ public boolean hasEncryptedPrivateKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getEncryptedPrivateKey() {
+ return encryptedPrivateKey_;
+ }
+
+ private void initFields() {
+ initialisationVector_ = com.google.protobuf.ByteString.EMPTY;
+ encryptedPrivateKey_ = com.google.protobuf.ByteString.EMPTY;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ if (!hasInitialisationVector()) {
+ memoizedIsInitialized = 0;
+ return false;
+ }
+ if (!hasEncryptedPrivateKey()) {
+ memoizedIsInitialized = 0;
+ return false;
+ }
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeBytes(1, initialisationVector_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBytes(2, encryptedPrivateKey_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(1, initialisationVector_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(2, encryptedPrivateKey_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.EncryptedPrivateKey parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.bitcoinj.wallet.Protos.EncryptedPrivateKey prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.bitcoinj.wallet.Protos.EncryptedPrivateKeyOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.bitcoinj.wallet.Protos.internal_static_wallet_EncryptedPrivateKey_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.bitcoinj.wallet.Protos.internal_static_wallet_EncryptedPrivateKey_fieldAccessorTable;
+ }
+
+ // Construct using org.bitcoinj.wallet.Protos.EncryptedPrivateKey.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ initialisationVector_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ encryptedPrivateKey_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.bitcoinj.wallet.Protos.EncryptedPrivateKey.getDescriptor();
+ }
+
+ public org.bitcoinj.wallet.Protos.EncryptedPrivateKey getDefaultInstanceForType() {
+ return org.bitcoinj.wallet.Protos.EncryptedPrivateKey.getDefaultInstance();
+ }
+
+ public org.bitcoinj.wallet.Protos.EncryptedPrivateKey build() {
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.bitcoinj.wallet.Protos.EncryptedPrivateKey buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.bitcoinj.wallet.Protos.EncryptedPrivateKey buildPartial() {
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey result = new org.bitcoinj.wallet.Protos.EncryptedPrivateKey(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.initialisationVector_ = initialisationVector_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.encryptedPrivateKey_ = encryptedPrivateKey_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.bitcoinj.wallet.Protos.EncryptedPrivateKey) {
+ return mergeFrom((org.bitcoinj.wallet.Protos.EncryptedPrivateKey)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.bitcoinj.wallet.Protos.EncryptedPrivateKey other) {
+ if (other == org.bitcoinj.wallet.Protos.EncryptedPrivateKey.getDefaultInstance()) return this;
+ if (other.hasInitialisationVector()) {
+ setInitialisationVector(other.getInitialisationVector());
+ }
+ if (other.hasEncryptedPrivateKey()) {
+ setEncryptedPrivateKey(other.getEncryptedPrivateKey());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ if (!hasInitialisationVector()) {
+
+ return false;
+ }
+ if (!hasEncryptedPrivateKey()) {
+
+ return false;
+ }
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 10: {
+ bitField0_ |= 0x00000001;
+ initialisationVector_ = input.readBytes();
+ break;
+ }
+ case 18: {
+ bitField0_ |= 0x00000002;
+ encryptedPrivateKey_ = input.readBytes();
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // required bytes initialisation_vector = 1;
+ private com.google.protobuf.ByteString initialisationVector_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasInitialisationVector() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public com.google.protobuf.ByteString getInitialisationVector() {
+ return initialisationVector_;
+ }
+ public Builder setInitialisationVector(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ initialisationVector_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearInitialisationVector() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ initialisationVector_ = getDefaultInstance().getInitialisationVector();
+ onChanged();
+ return this;
+ }
+
+ // required bytes encrypted_private_key = 2;
+ private com.google.protobuf.ByteString encryptedPrivateKey_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasEncryptedPrivateKey() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public com.google.protobuf.ByteString getEncryptedPrivateKey() {
+ return encryptedPrivateKey_;
+ }
+ public Builder setEncryptedPrivateKey(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000002;
+ encryptedPrivateKey_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearEncryptedPrivateKey() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ encryptedPrivateKey_ = getDefaultInstance().getEncryptedPrivateKey();
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:wallet.EncryptedPrivateKey)
+ }
+
+ static {
+ defaultInstance = new EncryptedPrivateKey(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:wallet.EncryptedPrivateKey)
+ }
+
public interface KeyOrBuilder
extends com.google.protobuf.MessageOrBuilder {
@@ -498,6 +915,11 @@ public final class Protos {
boolean hasPrivateKey();
com.google.protobuf.ByteString getPrivateKey();
+ // optional .wallet.EncryptedPrivateKey encrypted_private_key = 6;
+ boolean hasEncryptedPrivateKey();
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey getEncryptedPrivateKey();
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKeyOrBuilder getEncryptedPrivateKeyOrBuilder();
+
// optional bytes public_key = 3;
boolean hasPublicKey();
com.google.protobuf.ByteString getPublicKey();
@@ -541,9 +963,11 @@ public final class Protos {
public enum Type
implements com.google.protobuf.ProtocolMessageEnum {
ORIGINAL(0, 1),
+ ENCRYPTED_SCRYPT_AES(1, 2),
;
public static final int ORIGINAL_VALUE = 1;
+ public static final int ENCRYPTED_SCRYPT_AES_VALUE = 2;
public final int getNumber() { return value; }
@@ -551,6 +975,7 @@ public final class Protos {
public static Type valueOf(int value) {
switch (value) {
case 1: return ORIGINAL;
+ case 2: return ENCRYPTED_SCRYPT_AES;
default: return null;
}
}
@@ -581,7 +1006,7 @@ public final class Protos {
}
private static final Type[] VALUES = {
- ORIGINAL,
+ ORIGINAL, ENCRYPTED_SCRYPT_AES,
};
public static Type valueOf(
@@ -625,11 +1050,24 @@ public final class Protos {
return privateKey_;
}
+ // optional .wallet.EncryptedPrivateKey encrypted_private_key = 6;
+ public static final int ENCRYPTED_PRIVATE_KEY_FIELD_NUMBER = 6;
+ private org.bitcoinj.wallet.Protos.EncryptedPrivateKey encryptedPrivateKey_;
+ public boolean hasEncryptedPrivateKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public org.bitcoinj.wallet.Protos.EncryptedPrivateKey getEncryptedPrivateKey() {
+ return encryptedPrivateKey_;
+ }
+ public org.bitcoinj.wallet.Protos.EncryptedPrivateKeyOrBuilder getEncryptedPrivateKeyOrBuilder() {
+ return encryptedPrivateKey_;
+ }
+
// 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);
+ return ((bitField0_ & 0x00000008) == 0x00000008);
}
public com.google.protobuf.ByteString getPublicKey() {
return publicKey_;
@@ -639,7 +1077,7 @@ public final class Protos {
public static final int LABEL_FIELD_NUMBER = 4;
private java.lang.Object label_;
public boolean hasLabel() {
- return ((bitField0_ & 0x00000008) == 0x00000008);
+ return ((bitField0_ & 0x00000010) == 0x00000010);
}
public String getLabel() {
java.lang.Object ref = label_;
@@ -671,7 +1109,7 @@ public final class Protos {
public static final int CREATION_TIMESTAMP_FIELD_NUMBER = 5;
private long creationTimestamp_;
public boolean hasCreationTimestamp() {
- return ((bitField0_ & 0x00000010) == 0x00000010);
+ return ((bitField0_ & 0x00000020) == 0x00000020);
}
public long getCreationTimestamp() {
return creationTimestamp_;
@@ -680,6 +1118,7 @@ public final class Protos {
private void initFields() {
type_ = org.bitcoinj.wallet.Protos.Key.Type.ORIGINAL;
privateKey_ = com.google.protobuf.ByteString.EMPTY;
+ encryptedPrivateKey_ = org.bitcoinj.wallet.Protos.EncryptedPrivateKey.getDefaultInstance();
publicKey_ = com.google.protobuf.ByteString.EMPTY;
label_ = "";
creationTimestamp_ = 0L;
@@ -693,6 +1132,12 @@ public final class Protos {
memoizedIsInitialized = 0;
return false;
}
+ if (hasEncryptedPrivateKey()) {
+ if (!getEncryptedPrivateKey().isInitialized()) {
+ memoizedIsInitialized = 0;
+ return false;
+ }
+ }
memoizedIsInitialized = 1;
return true;
}
@@ -706,15 +1151,18 @@ public final class Protos {
if (((bitField0_ & 0x00000002) == 0x00000002)) {
output.writeBytes(2, privateKey_);
}
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeBytes(3, publicKey_);
}
- if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
output.writeBytes(4, getLabelBytes());
}
- if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
output.writeInt64(5, creationTimestamp_);
}
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeMessage(6, encryptedPrivateKey_);
+ }
getUnknownFields().writeTo(output);
}
@@ -732,18 +1180,22 @@ public final class Protos {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(2, privateKey_);
}
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(3, publicKey_);
}
- if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(4, getLabelBytes());
}
- if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
size += com.google.protobuf.CodedOutputStream
.computeInt64Size(5, creationTimestamp_);
}
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(6, encryptedPrivateKey_);
+ }
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -860,6 +1312,7 @@ public final class Protos {
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ getEncryptedPrivateKeyFieldBuilder();
}
}
private static Builder create() {
@@ -872,12 +1325,18 @@ public final class Protos {
bitField0_ = (bitField0_ & ~0x00000001);
privateKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000002);
- publicKey_ = com.google.protobuf.ByteString.EMPTY;
+ if (encryptedPrivateKeyBuilder_ == null) {
+ encryptedPrivateKey_ = org.bitcoinj.wallet.Protos.EncryptedPrivateKey.getDefaultInstance();
+ } else {
+ encryptedPrivateKeyBuilder_.clear();
+ }
bitField0_ = (bitField0_ & ~0x00000004);
- label_ = "";
+ publicKey_ = com.google.protobuf.ByteString.EMPTY;
bitField0_ = (bitField0_ & ~0x00000008);
- creationTimestamp_ = 0L;
+ label_ = "";
bitField0_ = (bitField0_ & ~0x00000010);
+ creationTimestamp_ = 0L;
+ bitField0_ = (bitField0_ & ~0x00000020);
return this;
}
@@ -927,14 +1386,22 @@ public final class Protos {
if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
to_bitField0_ |= 0x00000004;
}
- result.publicKey_ = publicKey_;
+ if (encryptedPrivateKeyBuilder_ == null) {
+ result.encryptedPrivateKey_ = encryptedPrivateKey_;
+ } else {
+ result.encryptedPrivateKey_ = encryptedPrivateKeyBuilder_.build();
+ }
if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
to_bitField0_ |= 0x00000008;
}
- result.label_ = label_;
+ result.publicKey_ = publicKey_;
if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
to_bitField0_ |= 0x00000010;
}
+ result.label_ = label_;
+ if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
+ to_bitField0_ |= 0x00000020;
+ }
result.creationTimestamp_ = creationTimestamp_;
result.bitField0_ = to_bitField0_;
onBuilt();
@@ -958,6 +1425,9 @@ public final class Protos {
if (other.hasPrivateKey()) {
setPrivateKey(other.getPrivateKey());
}
+ if (other.hasEncryptedPrivateKey()) {
+ mergeEncryptedPrivateKey(other.getEncryptedPrivateKey());
+ }
if (other.hasPublicKey()) {
setPublicKey(other.getPublicKey());
}
@@ -976,6 +1446,12 @@ public final class Protos {
return false;
}
+ if (hasEncryptedPrivateKey()) {
+ if (!getEncryptedPrivateKey().isInitialized()) {
+
+ return false;
+ }
+ }
return true;
}
@@ -1019,20 +1495,29 @@ public final class Protos {
break;
}
case 26: {
- bitField0_ |= 0x00000004;
+ bitField0_ |= 0x00000008;
publicKey_ = input.readBytes();
break;
}
case 34: {
- bitField0_ |= 0x00000008;
+ bitField0_ |= 0x00000010;
label_ = input.readBytes();
break;
}
case 40: {
- bitField0_ |= 0x00000010;
+ bitField0_ |= 0x00000020;
creationTimestamp_ = input.readInt64();
break;
}
+ case 50: {
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey.Builder subBuilder = org.bitcoinj.wallet.Protos.EncryptedPrivateKey.newBuilder();
+ if (hasEncryptedPrivateKey()) {
+ subBuilder.mergeFrom(getEncryptedPrivateKey());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setEncryptedPrivateKey(subBuilder.buildPartial());
+ break;
+ }
}
}
}
@@ -1087,10 +1572,100 @@ public final class Protos {
return this;
}
+ // optional .wallet.EncryptedPrivateKey encrypted_private_key = 6;
+ private org.bitcoinj.wallet.Protos.EncryptedPrivateKey encryptedPrivateKey_ = org.bitcoinj.wallet.Protos.EncryptedPrivateKey.getDefaultInstance();
+ private com.google.protobuf.SingleFieldBuilder<
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey, org.bitcoinj.wallet.Protos.EncryptedPrivateKey.Builder, org.bitcoinj.wallet.Protos.EncryptedPrivateKeyOrBuilder> encryptedPrivateKeyBuilder_;
+ public boolean hasEncryptedPrivateKey() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public org.bitcoinj.wallet.Protos.EncryptedPrivateKey getEncryptedPrivateKey() {
+ if (encryptedPrivateKeyBuilder_ == null) {
+ return encryptedPrivateKey_;
+ } else {
+ return encryptedPrivateKeyBuilder_.getMessage();
+ }
+ }
+ public Builder setEncryptedPrivateKey(org.bitcoinj.wallet.Protos.EncryptedPrivateKey value) {
+ if (encryptedPrivateKeyBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ encryptedPrivateKey_ = value;
+ onChanged();
+ } else {
+ encryptedPrivateKeyBuilder_.setMessage(value);
+ }
+ bitField0_ |= 0x00000004;
+ return this;
+ }
+ public Builder setEncryptedPrivateKey(
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey.Builder builderForValue) {
+ if (encryptedPrivateKeyBuilder_ == null) {
+ encryptedPrivateKey_ = builderForValue.build();
+ onChanged();
+ } else {
+ encryptedPrivateKeyBuilder_.setMessage(builderForValue.build());
+ }
+ bitField0_ |= 0x00000004;
+ return this;
+ }
+ public Builder mergeEncryptedPrivateKey(org.bitcoinj.wallet.Protos.EncryptedPrivateKey value) {
+ if (encryptedPrivateKeyBuilder_ == null) {
+ if (((bitField0_ & 0x00000004) == 0x00000004) &&
+ encryptedPrivateKey_ != org.bitcoinj.wallet.Protos.EncryptedPrivateKey.getDefaultInstance()) {
+ encryptedPrivateKey_ =
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey.newBuilder(encryptedPrivateKey_).mergeFrom(value).buildPartial();
+ } else {
+ encryptedPrivateKey_ = value;
+ }
+ onChanged();
+ } else {
+ encryptedPrivateKeyBuilder_.mergeFrom(value);
+ }
+ bitField0_ |= 0x00000004;
+ return this;
+ }
+ public Builder clearEncryptedPrivateKey() {
+ if (encryptedPrivateKeyBuilder_ == null) {
+ encryptedPrivateKey_ = org.bitcoinj.wallet.Protos.EncryptedPrivateKey.getDefaultInstance();
+ onChanged();
+ } else {
+ encryptedPrivateKeyBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000004);
+ return this;
+ }
+ public org.bitcoinj.wallet.Protos.EncryptedPrivateKey.Builder getEncryptedPrivateKeyBuilder() {
+ bitField0_ |= 0x00000004;
+ onChanged();
+ return getEncryptedPrivateKeyFieldBuilder().getBuilder();
+ }
+ public org.bitcoinj.wallet.Protos.EncryptedPrivateKeyOrBuilder getEncryptedPrivateKeyOrBuilder() {
+ if (encryptedPrivateKeyBuilder_ != null) {
+ return encryptedPrivateKeyBuilder_.getMessageOrBuilder();
+ } else {
+ return encryptedPrivateKey_;
+ }
+ }
+ private com.google.protobuf.SingleFieldBuilder<
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey, org.bitcoinj.wallet.Protos.EncryptedPrivateKey.Builder, org.bitcoinj.wallet.Protos.EncryptedPrivateKeyOrBuilder>
+ getEncryptedPrivateKeyFieldBuilder() {
+ if (encryptedPrivateKeyBuilder_ == null) {
+ encryptedPrivateKeyBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey, org.bitcoinj.wallet.Protos.EncryptedPrivateKey.Builder, org.bitcoinj.wallet.Protos.EncryptedPrivateKeyOrBuilder>(
+ encryptedPrivateKey_,
+ getParentForChildren(),
+ isClean());
+ encryptedPrivateKey_ = null;
+ }
+ return encryptedPrivateKeyBuilder_;
+ }
+
// optional bytes public_key = 3;
private com.google.protobuf.ByteString publicKey_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasPublicKey() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
+ return ((bitField0_ & 0x00000008) == 0x00000008);
}
public com.google.protobuf.ByteString getPublicKey() {
return publicKey_;
@@ -1099,13 +1674,13 @@ public final class Protos {
if (value == null) {
throw new NullPointerException();
}
- bitField0_ |= 0x00000004;
+ bitField0_ |= 0x00000008;
publicKey_ = value;
onChanged();
return this;
}
public Builder clearPublicKey() {
- bitField0_ = (bitField0_ & ~0x00000004);
+ bitField0_ = (bitField0_ & ~0x00000008);
publicKey_ = getDefaultInstance().getPublicKey();
onChanged();
return this;
@@ -1114,7 +1689,7 @@ public final class Protos {
// optional string label = 4;
private java.lang.Object label_ = "";
public boolean hasLabel() {
- return ((bitField0_ & 0x00000008) == 0x00000008);
+ return ((bitField0_ & 0x00000010) == 0x00000010);
}
public String getLabel() {
java.lang.Object ref = label_;
@@ -1130,19 +1705,19 @@ public final class Protos {
if (value == null) {
throw new NullPointerException();
}
- bitField0_ |= 0x00000008;
+ bitField0_ |= 0x00000010;
label_ = value;
onChanged();
return this;
}
public Builder clearLabel() {
- bitField0_ = (bitField0_ & ~0x00000008);
+ bitField0_ = (bitField0_ & ~0x00000010);
label_ = getDefaultInstance().getLabel();
onChanged();
return this;
}
void setLabel(com.google.protobuf.ByteString value) {
- bitField0_ |= 0x00000008;
+ bitField0_ |= 0x00000010;
label_ = value;
onChanged();
}
@@ -1150,19 +1725,19 @@ public final class Protos {
// optional int64 creation_timestamp = 5;
private long creationTimestamp_ ;
public boolean hasCreationTimestamp() {
- return ((bitField0_ & 0x00000010) == 0x00000010);
+ return ((bitField0_ & 0x00000020) == 0x00000020);
}
public long getCreationTimestamp() {
return creationTimestamp_;
}
public Builder setCreationTimestamp(long value) {
- bitField0_ |= 0x00000010;
+ bitField0_ |= 0x00000020;
creationTimestamp_ = value;
onChanged();
return this;
}
public Builder clearCreationTimestamp() {
- bitField0_ = (bitField0_ & ~0x00000010);
+ bitField0_ = (bitField0_ & ~0x00000020);
creationTimestamp_ = 0L;
onChanged();
return this;
@@ -4833,6 +5408,526 @@ public final class Protos {
// @@protoc_insertion_point(class_scope:wallet.Transaction)
}
+ public interface ScryptParametersOrBuilder
+ extends com.google.protobuf.MessageOrBuilder {
+
+ // required bytes salt = 1;
+ boolean hasSalt();
+ com.google.protobuf.ByteString getSalt();
+
+ // optional int64 n = 2 [default = 16384];
+ boolean hasN();
+ long getN();
+
+ // optional int32 r = 3 [default = 8];
+ boolean hasR();
+ int getR();
+
+ // optional int32 p = 4 [default = 1];
+ boolean hasP();
+ int getP();
+ }
+ public static final class ScryptParameters extends
+ com.google.protobuf.GeneratedMessage
+ implements ScryptParametersOrBuilder {
+ // Use ScryptParameters.newBuilder() to construct.
+ private ScryptParameters(Builder builder) {
+ super(builder);
+ }
+ private ScryptParameters(boolean noInit) {}
+
+ private static final ScryptParameters defaultInstance;
+ public static ScryptParameters getDefaultInstance() {
+ return defaultInstance;
+ }
+
+ public ScryptParameters getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.bitcoinj.wallet.Protos.internal_static_wallet_ScryptParameters_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.bitcoinj.wallet.Protos.internal_static_wallet_ScryptParameters_fieldAccessorTable;
+ }
+
+ private int bitField0_;
+ // required bytes salt = 1;
+ public static final int SALT_FIELD_NUMBER = 1;
+ private com.google.protobuf.ByteString salt_;
+ public boolean hasSalt() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public com.google.protobuf.ByteString getSalt() {
+ return salt_;
+ }
+
+ // optional int64 n = 2 [default = 16384];
+ public static final int N_FIELD_NUMBER = 2;
+ private long n_;
+ public boolean hasN() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public long getN() {
+ return n_;
+ }
+
+ // optional int32 r = 3 [default = 8];
+ public static final int R_FIELD_NUMBER = 3;
+ private int r_;
+ public boolean hasR() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public int getR() {
+ return r_;
+ }
+
+ // optional int32 p = 4 [default = 1];
+ public static final int P_FIELD_NUMBER = 4;
+ private int p_;
+ public boolean hasP() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public int getP() {
+ return p_;
+ }
+
+ private void initFields() {
+ salt_ = com.google.protobuf.ByteString.EMPTY;
+ n_ = 16384L;
+ r_ = 8;
+ p_ = 1;
+ }
+ private byte memoizedIsInitialized = -1;
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized != -1) return isInitialized == 1;
+
+ if (!hasSalt()) {
+ memoizedIsInitialized = 0;
+ return false;
+ }
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ getSerializedSize();
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ output.writeBytes(1, salt_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeInt64(2, n_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeInt32(3, r_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ output.writeInt32(4, p_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public int getSerializedSize() {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) == 0x00000001)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(1, salt_);
+ }
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt64Size(2, n_);
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(3, r_);
+ }
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(4, p_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSerializedSize = size;
+ return size;
+ }
+
+ private static final long serialVersionUID = 0L;
+ @java.lang.Override
+ protected java.lang.Object writeReplace()
+ throws java.io.ObjectStreamException {
+ return super.writeReplace();
+ }
+
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ Builder builder = newBuilder();
+ if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
+ return builder.buildParsed();
+ } else {
+ return null;
+ }
+ }
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input).buildParsed();
+ }
+ public static org.bitcoinj.wallet.Protos.ScryptParameters parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return newBuilder().mergeFrom(input, extensionRegistry)
+ .buildParsed();
+ }
+
+ public static Builder newBuilder() { return Builder.create(); }
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder(org.bitcoinj.wallet.Protos.ScryptParameters prototype) {
+ return newBuilder().mergeFrom(prototype);
+ }
+ public Builder toBuilder() { return newBuilder(this); }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder
+ implements org.bitcoinj.wallet.Protos.ScryptParametersOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.bitcoinj.wallet.Protos.internal_static_wallet_ScryptParameters_descriptor;
+ }
+
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.bitcoinj.wallet.Protos.internal_static_wallet_ScryptParameters_fieldAccessorTable;
+ }
+
+ // Construct using org.bitcoinj.wallet.Protos.ScryptParameters.newBuilder()
+ private Builder() {
+ maybeForceBuilderInitialization();
+ }
+
+ private Builder(BuilderParent parent) {
+ super(parent);
+ maybeForceBuilderInitialization();
+ }
+ private void maybeForceBuilderInitialization() {
+ if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+ }
+ }
+ private static Builder create() {
+ return new Builder();
+ }
+
+ public Builder clear() {
+ super.clear();
+ salt_ = com.google.protobuf.ByteString.EMPTY;
+ bitField0_ = (bitField0_ & ~0x00000001);
+ n_ = 16384L;
+ bitField0_ = (bitField0_ & ~0x00000002);
+ r_ = 8;
+ bitField0_ = (bitField0_ & ~0x00000004);
+ p_ = 1;
+ bitField0_ = (bitField0_ & ~0x00000008);
+ return this;
+ }
+
+ public Builder clone() {
+ return create().mergeFrom(buildPartial());
+ }
+
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.bitcoinj.wallet.Protos.ScryptParameters.getDescriptor();
+ }
+
+ public org.bitcoinj.wallet.Protos.ScryptParameters getDefaultInstanceForType() {
+ return org.bitcoinj.wallet.Protos.ScryptParameters.getDefaultInstance();
+ }
+
+ public org.bitcoinj.wallet.Protos.ScryptParameters build() {
+ org.bitcoinj.wallet.Protos.ScryptParameters result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ private org.bitcoinj.wallet.Protos.ScryptParameters buildParsed()
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ org.bitcoinj.wallet.Protos.ScryptParameters result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(
+ result).asInvalidProtocolBufferException();
+ }
+ return result;
+ }
+
+ public org.bitcoinj.wallet.Protos.ScryptParameters buildPartial() {
+ org.bitcoinj.wallet.Protos.ScryptParameters result = new org.bitcoinj.wallet.Protos.ScryptParameters(this);
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+ to_bitField0_ |= 0x00000001;
+ }
+ result.salt_ = salt_;
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.n_ = n_;
+ if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+ to_bitField0_ |= 0x00000004;
+ }
+ result.r_ = r_;
+ if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+ to_bitField0_ |= 0x00000008;
+ }
+ result.p_ = p_;
+ result.bitField0_ = to_bitField0_;
+ onBuilt();
+ return result;
+ }
+
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.bitcoinj.wallet.Protos.ScryptParameters) {
+ return mergeFrom((org.bitcoinj.wallet.Protos.ScryptParameters)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.bitcoinj.wallet.Protos.ScryptParameters other) {
+ if (other == org.bitcoinj.wallet.Protos.ScryptParameters.getDefaultInstance()) return this;
+ if (other.hasSalt()) {
+ setSalt(other.getSalt());
+ }
+ if (other.hasN()) {
+ setN(other.getN());
+ }
+ if (other.hasR()) {
+ setR(other.getR());
+ }
+ if (other.hasP()) {
+ setP(other.getP());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ return this;
+ }
+
+ public final boolean isInitialized() {
+ if (!hasSalt()) {
+
+ return false;
+ }
+ return true;
+ }
+
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+ com.google.protobuf.UnknownFieldSet.newBuilder(
+ this.getUnknownFields());
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ default: {
+ if (!parseUnknownField(input, unknownFields,
+ extensionRegistry, tag)) {
+ this.setUnknownFields(unknownFields.build());
+ onChanged();
+ return this;
+ }
+ break;
+ }
+ case 10: {
+ bitField0_ |= 0x00000001;
+ salt_ = input.readBytes();
+ break;
+ }
+ case 16: {
+ bitField0_ |= 0x00000002;
+ n_ = input.readInt64();
+ break;
+ }
+ case 24: {
+ bitField0_ |= 0x00000004;
+ r_ = input.readInt32();
+ break;
+ }
+ case 32: {
+ bitField0_ |= 0x00000008;
+ p_ = input.readInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ private int bitField0_;
+
+ // required bytes salt = 1;
+ private com.google.protobuf.ByteString salt_ = com.google.protobuf.ByteString.EMPTY;
+ public boolean hasSalt() {
+ return ((bitField0_ & 0x00000001) == 0x00000001);
+ }
+ public com.google.protobuf.ByteString getSalt() {
+ return salt_;
+ }
+ public Builder setSalt(com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000001;
+ salt_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearSalt() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ salt_ = getDefaultInstance().getSalt();
+ onChanged();
+ return this;
+ }
+
+ // optional int64 n = 2 [default = 16384];
+ private long n_ = 16384L;
+ public boolean hasN() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ public long getN() {
+ return n_;
+ }
+ public Builder setN(long value) {
+ bitField0_ |= 0x00000002;
+ n_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearN() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ n_ = 16384L;
+ onChanged();
+ return this;
+ }
+
+ // optional int32 r = 3 [default = 8];
+ private int r_ = 8;
+ public boolean hasR() {
+ return ((bitField0_ & 0x00000004) == 0x00000004);
+ }
+ public int getR() {
+ return r_;
+ }
+ public Builder setR(int value) {
+ bitField0_ |= 0x00000004;
+ r_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearR() {
+ bitField0_ = (bitField0_ & ~0x00000004);
+ r_ = 8;
+ onChanged();
+ return this;
+ }
+
+ // optional int32 p = 4 [default = 1];
+ private int p_ = 1;
+ public boolean hasP() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public int getP() {
+ return p_;
+ }
+ public Builder setP(int value) {
+ bitField0_ |= 0x00000008;
+ p_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearP() {
+ bitField0_ = (bitField0_ & ~0x00000008);
+ p_ = 1;
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:wallet.ScryptParameters)
+ }
+
+ static {
+ defaultInstance = new ScryptParameters(true);
+ defaultInstance.initFields();
+ }
+
+ // @@protoc_insertion_point(class_scope:wallet.ScryptParameters)
+ }
+
public interface ExtensionOrBuilder
extends com.google.protobuf.MessageOrBuilder {
@@ -5360,7 +6455,7 @@ public final class Protos {
boolean hasLastSeenBlockHash();
com.google.protobuf.ByteString getLastSeenBlockHash();
- // optional uint32 last_seen_block_height = 5;
+ // optional uint32 last_seen_block_height = 12;
boolean hasLastSeenBlockHeight();
int getLastSeenBlockHeight();
@@ -5384,6 +6479,19 @@ public final class Protos {
org.bitcoinj.wallet.Protos.TransactionOrBuilder getTransactionOrBuilder(
int index);
+ // optional .wallet.Wallet.EncryptionType encryption_type = 5 [default = UNENCRYPTED];
+ boolean hasEncryptionType();
+ org.bitcoinj.wallet.Protos.Wallet.EncryptionType getEncryptionType();
+
+ // optional .wallet.ScryptParameters encryption_parameters = 6;
+ boolean hasEncryptionParameters();
+ org.bitcoinj.wallet.Protos.ScryptParameters getEncryptionParameters();
+ org.bitcoinj.wallet.Protos.ScryptParametersOrBuilder getEncryptionParametersOrBuilder();
+
+ // optional int32 version = 7;
+ boolean hasVersion();
+ int getVersion();
+
// repeated .wallet.Extension extension = 10;
java.util.List
getExtensionList();
@@ -5393,6 +6501,10 @@ public final class Protos {
getExtensionOrBuilderList();
org.bitcoinj.wallet.Protos.ExtensionOrBuilder getExtensionOrBuilder(
int index);
+
+ // optional string description = 11;
+ boolean hasDescription();
+ String getDescription();
}
public static final class Wallet extends
com.google.protobuf.GeneratedMessage
@@ -5422,6 +6534,75 @@ public final class Protos {
return org.bitcoinj.wallet.Protos.internal_static_wallet_Wallet_fieldAccessorTable;
}
+ public enum EncryptionType
+ implements com.google.protobuf.ProtocolMessageEnum {
+ UNENCRYPTED(0, 1),
+ ENCRYPTED_SCRYPT_AES(1, 2),
+ ;
+
+ public static final int UNENCRYPTED_VALUE = 1;
+ public static final int ENCRYPTED_SCRYPT_AES_VALUE = 2;
+
+
+ public final int getNumber() { return value; }
+
+ public static EncryptionType valueOf(int value) {
+ switch (value) {
+ case 1: return UNENCRYPTED;
+ case 2: return ENCRYPTED_SCRYPT_AES;
+ default: return null;
+ }
+ }
+
+ public static com.google.protobuf.Internal.EnumLiteMap
+ internalGetValueMap() {
+ return internalValueMap;
+ }
+ private static com.google.protobuf.Internal.EnumLiteMap
+ internalValueMap =
+ new com.google.protobuf.Internal.EnumLiteMap() {
+ public EncryptionType findValueByNumber(int number) {
+ return EncryptionType.valueOf(number);
+ }
+ };
+
+ public final com.google.protobuf.Descriptors.EnumValueDescriptor
+ getValueDescriptor() {
+ return getDescriptor().getValues().get(index);
+ }
+ public final com.google.protobuf.Descriptors.EnumDescriptor
+ getDescriptorForType() {
+ return getDescriptor();
+ }
+ public static final com.google.protobuf.Descriptors.EnumDescriptor
+ getDescriptor() {
+ return org.bitcoinj.wallet.Protos.Wallet.getDescriptor().getEnumTypes().get(0);
+ }
+
+ private static final EncryptionType[] VALUES = {
+ UNENCRYPTED, ENCRYPTED_SCRYPT_AES,
+ };
+
+ public static EncryptionType valueOf(
+ com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
+ if (desc.getType() != getDescriptor()) {
+ throw new java.lang.IllegalArgumentException(
+ "EnumValueDescriptor is not for this type.");
+ }
+ return VALUES[desc.getIndex()];
+ }
+
+ private final int index;
+ private final int value;
+
+ private EncryptionType(int index, int value) {
+ this.index = index;
+ this.value = value;
+ }
+
+ // @@protoc_insertion_point(enum_scope:wallet.Wallet.EncryptionType)
+ }
+
private int bitField0_;
// required string network_identifier = 1;
public static final int NETWORK_IDENTIFIER_FIELD_NUMBER = 1;
@@ -5465,8 +6646,8 @@ public final class Protos {
return lastSeenBlockHash_;
}
- // optional uint32 last_seen_block_height = 5;
- public static final int LAST_SEEN_BLOCK_HEIGHT_FIELD_NUMBER = 5;
+ // optional uint32 last_seen_block_height = 12;
+ public static final int LAST_SEEN_BLOCK_HEIGHT_FIELD_NUMBER = 12;
private int lastSeenBlockHeight_;
public boolean hasLastSeenBlockHeight() {
return ((bitField0_ & 0x00000004) == 0x00000004);
@@ -5517,6 +6698,39 @@ public final class Protos {
return transaction_.get(index);
}
+ // optional .wallet.Wallet.EncryptionType encryption_type = 5 [default = UNENCRYPTED];
+ public static final int ENCRYPTION_TYPE_FIELD_NUMBER = 5;
+ private org.bitcoinj.wallet.Protos.Wallet.EncryptionType encryptionType_;
+ public boolean hasEncryptionType() {
+ return ((bitField0_ & 0x00000008) == 0x00000008);
+ }
+ public org.bitcoinj.wallet.Protos.Wallet.EncryptionType getEncryptionType() {
+ return encryptionType_;
+ }
+
+ // optional .wallet.ScryptParameters encryption_parameters = 6;
+ public static final int ENCRYPTION_PARAMETERS_FIELD_NUMBER = 6;
+ private org.bitcoinj.wallet.Protos.ScryptParameters encryptionParameters_;
+ public boolean hasEncryptionParameters() {
+ return ((bitField0_ & 0x00000010) == 0x00000010);
+ }
+ public org.bitcoinj.wallet.Protos.ScryptParameters getEncryptionParameters() {
+ return encryptionParameters_;
+ }
+ public org.bitcoinj.wallet.Protos.ScryptParametersOrBuilder getEncryptionParametersOrBuilder() {
+ return encryptionParameters_;
+ }
+
+ // optional int32 version = 7;
+ public static final int VERSION_FIELD_NUMBER = 7;
+ private int version_;
+ public boolean hasVersion() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ public int getVersion() {
+ return version_;
+ }
+
// repeated .wallet.Extension extension = 10;
public static final int EXTENSION_FIELD_NUMBER = 10;
private java.util.List extension_;
@@ -5538,13 +6752,49 @@ public final class Protos {
return extension_.get(index);
}
+ // optional string description = 11;
+ public static final int DESCRIPTION_FIELD_NUMBER = 11;
+ private java.lang.Object description_;
+ public boolean hasDescription() {
+ return ((bitField0_ & 0x00000040) == 0x00000040);
+ }
+ public String getDescription() {
+ java.lang.Object ref = description_;
+ if (ref instanceof String) {
+ return (String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ String s = bs.toStringUtf8();
+ if (com.google.protobuf.Internal.isValidUtf8(bs)) {
+ description_ = s;
+ }
+ return s;
+ }
+ }
+ private com.google.protobuf.ByteString getDescriptionBytes() {
+ java.lang.Object ref = description_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8((String) ref);
+ description_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
private void initFields() {
networkIdentifier_ = "";
lastSeenBlockHash_ = com.google.protobuf.ByteString.EMPTY;
lastSeenBlockHeight_ = 0;
key_ = java.util.Collections.emptyList();
transaction_ = java.util.Collections.emptyList();
+ encryptionType_ = org.bitcoinj.wallet.Protos.Wallet.EncryptionType.UNENCRYPTED;
+ encryptionParameters_ = org.bitcoinj.wallet.Protos.ScryptParameters.getDefaultInstance();
+ version_ = 0;
extension_ = java.util.Collections.emptyList();
+ description_ = "";
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@@ -5567,6 +6817,12 @@ public final class Protos {
return false;
}
}
+ if (hasEncryptionParameters()) {
+ if (!getEncryptionParameters().isInitialized()) {
+ memoizedIsInitialized = 0;
+ return false;
+ }
+ }
for (int i = 0; i < getExtensionCount(); i++) {
if (!getExtension(i).isInitialized()) {
memoizedIsInitialized = 0;
@@ -5592,12 +6848,24 @@ public final class Protos {
for (int i = 0; i < transaction_.size(); i++) {
output.writeMessage(4, transaction_.get(i));
}
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- output.writeUInt32(5, lastSeenBlockHeight_);
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
+ output.writeEnum(5, encryptionType_.getNumber());
+ }
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ output.writeMessage(6, encryptionParameters_);
+ }
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ output.writeInt32(7, version_);
}
for (int i = 0; i < extension_.size(); i++) {
output.writeMessage(10, extension_.get(i));
}
+ if (((bitField0_ & 0x00000040) == 0x00000040)) {
+ output.writeBytes(11, getDescriptionBytes());
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ output.writeUInt32(12, lastSeenBlockHeight_);
+ }
getUnknownFields().writeTo(output);
}
@@ -5623,14 +6891,30 @@ public final class Protos {
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(4, transaction_.get(i));
}
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ if (((bitField0_ & 0x00000008) == 0x00000008)) {
size += com.google.protobuf.CodedOutputStream
- .computeUInt32Size(5, lastSeenBlockHeight_);
+ .computeEnumSize(5, encryptionType_.getNumber());
+ }
+ if (((bitField0_ & 0x00000010) == 0x00000010)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeMessageSize(6, encryptionParameters_);
+ }
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(7, version_);
}
for (int i = 0; i < extension_.size(); i++) {
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(10, extension_.get(i));
}
+ if (((bitField0_ & 0x00000040) == 0x00000040)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(11, getDescriptionBytes());
+ }
+ if (((bitField0_ & 0x00000004) == 0x00000004)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeUInt32Size(12, lastSeenBlockHeight_);
+ }
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -5749,6 +7033,7 @@ public final class Protos {
if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
getKeyFieldBuilder();
getTransactionFieldBuilder();
+ getEncryptionParametersFieldBuilder();
getExtensionFieldBuilder();
}
}
@@ -5776,12 +7061,24 @@ public final class Protos {
} else {
transactionBuilder_.clear();
}
+ encryptionType_ = org.bitcoinj.wallet.Protos.Wallet.EncryptionType.UNENCRYPTED;
+ bitField0_ = (bitField0_ & ~0x00000020);
+ if (encryptionParametersBuilder_ == null) {
+ encryptionParameters_ = org.bitcoinj.wallet.Protos.ScryptParameters.getDefaultInstance();
+ } else {
+ encryptionParametersBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000040);
+ version_ = 0;
+ bitField0_ = (bitField0_ & ~0x00000080);
if (extensionBuilder_ == null) {
extension_ = java.util.Collections.emptyList();
- bitField0_ = (bitField0_ & ~0x00000020);
+ bitField0_ = (bitField0_ & ~0x00000100);
} else {
extensionBuilder_.clear();
}
+ description_ = "";
+ bitField0_ = (bitField0_ & ~0x00000200);
return this;
}
@@ -5850,15 +7147,35 @@ public final class Protos {
} else {
result.transaction_ = transactionBuilder_.build();
}
+ if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
+ to_bitField0_ |= 0x00000008;
+ }
+ result.encryptionType_ = encryptionType_;
+ if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
+ to_bitField0_ |= 0x00000010;
+ }
+ if (encryptionParametersBuilder_ == null) {
+ result.encryptionParameters_ = encryptionParameters_;
+ } else {
+ result.encryptionParameters_ = encryptionParametersBuilder_.build();
+ }
+ if (((from_bitField0_ & 0x00000080) == 0x00000080)) {
+ to_bitField0_ |= 0x00000020;
+ }
+ result.version_ = version_;
if (extensionBuilder_ == null) {
- if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ if (((bitField0_ & 0x00000100) == 0x00000100)) {
extension_ = java.util.Collections.unmodifiableList(extension_);
- bitField0_ = (bitField0_ & ~0x00000020);
+ bitField0_ = (bitField0_ & ~0x00000100);
}
result.extension_ = extension_;
} else {
result.extension_ = extensionBuilder_.build();
}
+ if (((from_bitField0_ & 0x00000200) == 0x00000200)) {
+ to_bitField0_ |= 0x00000040;
+ }
+ result.description_ = description_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@@ -5936,11 +7253,20 @@ public final class Protos {
}
}
}
+ if (other.hasEncryptionType()) {
+ setEncryptionType(other.getEncryptionType());
+ }
+ if (other.hasEncryptionParameters()) {
+ mergeEncryptionParameters(other.getEncryptionParameters());
+ }
+ if (other.hasVersion()) {
+ setVersion(other.getVersion());
+ }
if (extensionBuilder_ == null) {
if (!other.extension_.isEmpty()) {
if (extension_.isEmpty()) {
extension_ = other.extension_;
- bitField0_ = (bitField0_ & ~0x00000020);
+ bitField0_ = (bitField0_ & ~0x00000100);
} else {
ensureExtensionIsMutable();
extension_.addAll(other.extension_);
@@ -5953,7 +7279,7 @@ public final class Protos {
extensionBuilder_.dispose();
extensionBuilder_ = null;
extension_ = other.extension_;
- bitField0_ = (bitField0_ & ~0x00000020);
+ bitField0_ = (bitField0_ & ~0x00000100);
extensionBuilder_ =
com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
getExtensionFieldBuilder() : null;
@@ -5962,6 +7288,9 @@ public final class Protos {
}
}
}
+ if (other.hasDescription()) {
+ setDescription(other.getDescription());
+ }
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@@ -5983,6 +7312,12 @@ public final class Protos {
return false;
}
}
+ if (hasEncryptionParameters()) {
+ if (!getEncryptionParameters().isInitialized()) {
+
+ return false;
+ }
+ }
for (int i = 0; i < getExtensionCount(); i++) {
if (!getExtension(i).isInitialized()) {
@@ -6038,8 +7373,28 @@ public final class Protos {
break;
}
case 40: {
- bitField0_ |= 0x00000004;
- lastSeenBlockHeight_ = input.readUInt32();
+ int rawValue = input.readEnum();
+ org.bitcoinj.wallet.Protos.Wallet.EncryptionType value = org.bitcoinj.wallet.Protos.Wallet.EncryptionType.valueOf(rawValue);
+ if (value == null) {
+ unknownFields.mergeVarintField(5, rawValue);
+ } else {
+ bitField0_ |= 0x00000020;
+ encryptionType_ = value;
+ }
+ break;
+ }
+ case 50: {
+ org.bitcoinj.wallet.Protos.ScryptParameters.Builder subBuilder = org.bitcoinj.wallet.Protos.ScryptParameters.newBuilder();
+ if (hasEncryptionParameters()) {
+ subBuilder.mergeFrom(getEncryptionParameters());
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ setEncryptionParameters(subBuilder.buildPartial());
+ break;
+ }
+ case 56: {
+ bitField0_ |= 0x00000080;
+ version_ = input.readInt32();
break;
}
case 82: {
@@ -6048,6 +7403,16 @@ public final class Protos {
addExtension(subBuilder.buildPartial());
break;
}
+ case 90: {
+ bitField0_ |= 0x00000200;
+ description_ = input.readBytes();
+ break;
+ }
+ case 96: {
+ bitField0_ |= 0x00000004;
+ lastSeenBlockHeight_ = input.readUInt32();
+ break;
+ }
}
}
}
@@ -6114,7 +7479,7 @@ public final class Protos {
return this;
}
- // optional uint32 last_seen_block_height = 5;
+ // optional uint32 last_seen_block_height = 12;
private int lastSeenBlockHeight_ ;
public boolean hasLastSeenBlockHeight() {
return ((bitField0_ & 0x00000004) == 0x00000004);
@@ -6507,13 +7872,148 @@ public final class Protos {
return transactionBuilder_;
}
+ // optional .wallet.Wallet.EncryptionType encryption_type = 5 [default = UNENCRYPTED];
+ private org.bitcoinj.wallet.Protos.Wallet.EncryptionType encryptionType_ = org.bitcoinj.wallet.Protos.Wallet.EncryptionType.UNENCRYPTED;
+ public boolean hasEncryptionType() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ public org.bitcoinj.wallet.Protos.Wallet.EncryptionType getEncryptionType() {
+ return encryptionType_;
+ }
+ public Builder setEncryptionType(org.bitcoinj.wallet.Protos.Wallet.EncryptionType value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000020;
+ encryptionType_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearEncryptionType() {
+ bitField0_ = (bitField0_ & ~0x00000020);
+ encryptionType_ = org.bitcoinj.wallet.Protos.Wallet.EncryptionType.UNENCRYPTED;
+ onChanged();
+ return this;
+ }
+
+ // optional .wallet.ScryptParameters encryption_parameters = 6;
+ private org.bitcoinj.wallet.Protos.ScryptParameters encryptionParameters_ = org.bitcoinj.wallet.Protos.ScryptParameters.getDefaultInstance();
+ private com.google.protobuf.SingleFieldBuilder<
+ org.bitcoinj.wallet.Protos.ScryptParameters, org.bitcoinj.wallet.Protos.ScryptParameters.Builder, org.bitcoinj.wallet.Protos.ScryptParametersOrBuilder> encryptionParametersBuilder_;
+ public boolean hasEncryptionParameters() {
+ return ((bitField0_ & 0x00000040) == 0x00000040);
+ }
+ public org.bitcoinj.wallet.Protos.ScryptParameters getEncryptionParameters() {
+ if (encryptionParametersBuilder_ == null) {
+ return encryptionParameters_;
+ } else {
+ return encryptionParametersBuilder_.getMessage();
+ }
+ }
+ public Builder setEncryptionParameters(org.bitcoinj.wallet.Protos.ScryptParameters value) {
+ if (encryptionParametersBuilder_ == null) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ encryptionParameters_ = value;
+ onChanged();
+ } else {
+ encryptionParametersBuilder_.setMessage(value);
+ }
+ bitField0_ |= 0x00000040;
+ return this;
+ }
+ public Builder setEncryptionParameters(
+ org.bitcoinj.wallet.Protos.ScryptParameters.Builder builderForValue) {
+ if (encryptionParametersBuilder_ == null) {
+ encryptionParameters_ = builderForValue.build();
+ onChanged();
+ } else {
+ encryptionParametersBuilder_.setMessage(builderForValue.build());
+ }
+ bitField0_ |= 0x00000040;
+ return this;
+ }
+ public Builder mergeEncryptionParameters(org.bitcoinj.wallet.Protos.ScryptParameters value) {
+ if (encryptionParametersBuilder_ == null) {
+ if (((bitField0_ & 0x00000040) == 0x00000040) &&
+ encryptionParameters_ != org.bitcoinj.wallet.Protos.ScryptParameters.getDefaultInstance()) {
+ encryptionParameters_ =
+ org.bitcoinj.wallet.Protos.ScryptParameters.newBuilder(encryptionParameters_).mergeFrom(value).buildPartial();
+ } else {
+ encryptionParameters_ = value;
+ }
+ onChanged();
+ } else {
+ encryptionParametersBuilder_.mergeFrom(value);
+ }
+ bitField0_ |= 0x00000040;
+ return this;
+ }
+ public Builder clearEncryptionParameters() {
+ if (encryptionParametersBuilder_ == null) {
+ encryptionParameters_ = org.bitcoinj.wallet.Protos.ScryptParameters.getDefaultInstance();
+ onChanged();
+ } else {
+ encryptionParametersBuilder_.clear();
+ }
+ bitField0_ = (bitField0_ & ~0x00000040);
+ return this;
+ }
+ public org.bitcoinj.wallet.Protos.ScryptParameters.Builder getEncryptionParametersBuilder() {
+ bitField0_ |= 0x00000040;
+ onChanged();
+ return getEncryptionParametersFieldBuilder().getBuilder();
+ }
+ public org.bitcoinj.wallet.Protos.ScryptParametersOrBuilder getEncryptionParametersOrBuilder() {
+ if (encryptionParametersBuilder_ != null) {
+ return encryptionParametersBuilder_.getMessageOrBuilder();
+ } else {
+ return encryptionParameters_;
+ }
+ }
+ private com.google.protobuf.SingleFieldBuilder<
+ org.bitcoinj.wallet.Protos.ScryptParameters, org.bitcoinj.wallet.Protos.ScryptParameters.Builder, org.bitcoinj.wallet.Protos.ScryptParametersOrBuilder>
+ getEncryptionParametersFieldBuilder() {
+ if (encryptionParametersBuilder_ == null) {
+ encryptionParametersBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+ org.bitcoinj.wallet.Protos.ScryptParameters, org.bitcoinj.wallet.Protos.ScryptParameters.Builder, org.bitcoinj.wallet.Protos.ScryptParametersOrBuilder>(
+ encryptionParameters_,
+ getParentForChildren(),
+ isClean());
+ encryptionParameters_ = null;
+ }
+ return encryptionParametersBuilder_;
+ }
+
+ // optional int32 version = 7;
+ private int version_ ;
+ public boolean hasVersion() {
+ return ((bitField0_ & 0x00000080) == 0x00000080);
+ }
+ public int getVersion() {
+ return version_;
+ }
+ public Builder setVersion(int value) {
+ bitField0_ |= 0x00000080;
+ version_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearVersion() {
+ bitField0_ = (bitField0_ & ~0x00000080);
+ version_ = 0;
+ onChanged();
+ return this;
+ }
+
// repeated .wallet.Extension extension = 10;
private java.util.List extension_ =
java.util.Collections.emptyList();
private void ensureExtensionIsMutable() {
- if (!((bitField0_ & 0x00000020) == 0x00000020)) {
+ if (!((bitField0_ & 0x00000100) == 0x00000100)) {
extension_ = new java.util.ArrayList(extension_);
- bitField0_ |= 0x00000020;
+ bitField0_ |= 0x00000100;
}
}
@@ -6629,7 +8129,7 @@ public final class Protos {
public Builder clearExtension() {
if (extensionBuilder_ == null) {
extension_ = java.util.Collections.emptyList();
- bitField0_ = (bitField0_ & ~0x00000020);
+ bitField0_ = (bitField0_ & ~0x00000100);
onChanged();
} else {
extensionBuilder_.clear();
@@ -6685,7 +8185,7 @@ public final class Protos {
extensionBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
org.bitcoinj.wallet.Protos.Extension, org.bitcoinj.wallet.Protos.Extension.Builder, org.bitcoinj.wallet.Protos.ExtensionOrBuilder>(
extension_,
- ((bitField0_ & 0x00000020) == 0x00000020),
+ ((bitField0_ & 0x00000100) == 0x00000100),
getParentForChildren(),
isClean());
extension_ = null;
@@ -6693,6 +8193,42 @@ public final class Protos {
return extensionBuilder_;
}
+ // optional string description = 11;
+ private java.lang.Object description_ = "";
+ public boolean hasDescription() {
+ return ((bitField0_ & 0x00000200) == 0x00000200);
+ }
+ public String getDescription() {
+ java.lang.Object ref = description_;
+ if (!(ref instanceof String)) {
+ String s = ((com.google.protobuf.ByteString) ref).toStringUtf8();
+ description_ = s;
+ return s;
+ } else {
+ return (String) ref;
+ }
+ }
+ public Builder setDescription(String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000200;
+ description_ = value;
+ onChanged();
+ return this;
+ }
+ public Builder clearDescription() {
+ bitField0_ = (bitField0_ & ~0x00000200);
+ description_ = getDefaultInstance().getDescription();
+ onChanged();
+ return this;
+ }
+ void setDescription(com.google.protobuf.ByteString value) {
+ bitField0_ |= 0x00000200;
+ description_ = value;
+ onChanged();
+ }
+
// @@protoc_insertion_point(builder_scope:wallet.Wallet)
}
@@ -6709,6 +8245,11 @@ public final class Protos {
private static
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_wallet_PeerAddress_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_wallet_EncryptedPrivateKey_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_wallet_EncryptedPrivateKey_fieldAccessorTable;
private static com.google.protobuf.Descriptors.Descriptor
internal_static_wallet_Key_descriptor;
private static
@@ -6734,6 +8275,11 @@ public final class Protos {
private static
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_wallet_Transaction_fieldAccessorTable;
+ private static com.google.protobuf.Descriptors.Descriptor
+ internal_static_wallet_ScryptParameters_descriptor;
+ private static
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_wallet_ScryptParameters_fieldAccessorTable;
private static com.google.protobuf.Descriptors.Descriptor
internal_static_wallet_Extension_descriptor;
private static
@@ -6755,45 +8301,57 @@ public final class Protos {
java.lang.String[] descriptorData = {
"\n\rbitcoin.proto\022\006wallet\"A\n\013PeerAddress\022\022" +
"\n\nip_address\030\001 \002(\014\022\014\n\004port\030\002 \002(\r\022\020\n\010serv" +
- "ices\030\003 \002(\004\"\217\001\n\003Key\022\036\n\004type\030\001 \002(\0162\020.walle" +
- "t.Key.Type\022\023\n\013private_key\030\002 \001(\014\022\022\n\npubli" +
- "c_key\030\003 \001(\014\022\r\n\005label\030\004 \001(\t\022\032\n\022creation_t" +
- "imestamp\030\005 \001(\003\"\024\n\004Type\022\014\n\010ORIGINAL\020\001\"\203\001\n" +
- "\020TransactionInput\022\"\n\032transaction_out_poi" +
- "nt_hash\030\001 \002(\014\022#\n\033transaction_out_point_i" +
- "ndex\030\002 \002(\005\022\024\n\014script_bytes\030\003 \002(\014\022\020\n\010sequ" +
- "ence\030\004 \001(\r\"\177\n\021TransactionOutput\022\r\n\005value",
- "\030\001 \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022!\n\031spent_by" +
- "_transaction_hash\030\003 \001(\014\022\"\n\032spent_by_tran" +
- "saction_index\030\004 \001(\005\"\246\003\n\025TransactionConfi" +
- "dence\0220\n\004type\030\001 \001(\0162\".wallet.Transaction" +
- "Confidence.Type\022\032\n\022appeared_at_height\030\002 " +
- "\001(\005\022\036\n\026overriding_transaction\030\003 \001(\014\022\r\n\005d" +
- "epth\030\004 \001(\005\022\021\n\twork_done\030\005 \001(\003\022)\n\014broadca" +
- "st_by\030\006 \003(\0132\023.wallet.PeerAddress\0224\n\006sour" +
- "ce\030\007 \001(\0162$.wallet.TransactionConfidence." +
- "Source\"Y\n\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020",
- "\001\022\025\n\021NOT_SEEN_IN_CHAIN\020\002\022\025\n\021NOT_IN_BEST_" +
- "CHAIN\020\003\022\010\n\004DEAD\020\004\"A\n\006Source\022\022\n\016SOURCE_UN" +
- "KNOWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017\n\013SOURCE_SE" +
- "LF\020\002\"\211\003\n\013Transaction\022\017\n\007version\030\001 \002(\005\022\014\n" +
- "\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.wallet.Trans" +
- "action.Pool\022\021\n\tlock_time\030\004 \001(\r\022\022\n\nupdate" +
- "d_at\030\005 \001(\003\0223\n\021transaction_input\030\006 \003(\0132\030." +
- "wallet.TransactionInput\0225\n\022transaction_o" +
- "utput\030\007 \003(\0132\031.wallet.TransactionOutput\022\022" +
- "\n\nblock_hash\030\010 \003(\014\0221\n\nconfidence\030\t \001(\0132\035",
- ".wallet.TransactionConfidence\"Y\n\004Pool\022\013\n" +
- "\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004D" +
- "EAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022" +
- "\"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022" +
- "\021\n\tmandatory\030\003 \002(\010\"\314\001\n\006Wallet\022\032\n\022network" +
- "_identifier\030\001 \002(\t\022\034\n\024last_seen_block_has" +
- "h\030\002 \001(\014\022\036\n\026last_seen_block_height\030\005 \001(\r\022" +
- "\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013transaction" +
- "\030\004 \003(\0132\023.wallet.Transaction\022$\n\textension" +
- "\030\n \003(\0132\021.wallet.ExtensionB\035\n\023org.bitcoin",
- "j.walletB\006Protos"
+ "ices\030\003 \002(\004\"S\n\023EncryptedPrivateKey\022\035\n\025ini" +
+ "tialisation_vector\030\001 \002(\014\022\035\n\025encrypted_pr" +
+ "ivate_key\030\002 \002(\014\"\345\001\n\003Key\022\036\n\004type\030\001 \002(\0162\020." +
+ "wallet.Key.Type\022\023\n\013private_key\030\002 \001(\014\022:\n\025" +
+ "encrypted_private_key\030\006 \001(\0132\033.wallet.Enc" +
+ "ryptedPrivateKey\022\022\n\npublic_key\030\003 \001(\014\022\r\n\005" +
+ "label\030\004 \001(\t\022\032\n\022creation_timestamp\030\005 \001(\003\"" +
+ ".\n\004Type\022\014\n\010ORIGINAL\020\001\022\030\n\024ENCRYPTED_SCRYP",
+ "T_AES\020\002\"\203\001\n\020TransactionInput\022\"\n\032transact" +
+ "ion_out_point_hash\030\001 \002(\014\022#\n\033transaction_" +
+ "out_point_index\030\002 \002(\005\022\024\n\014script_bytes\030\003 " +
+ "\002(\014\022\020\n\010sequence\030\004 \001(\r\"\177\n\021TransactionOutp" +
+ "ut\022\r\n\005value\030\001 \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022" +
+ "!\n\031spent_by_transaction_hash\030\003 \001(\014\022\"\n\032sp" +
+ "ent_by_transaction_index\030\004 \001(\005\"\246\003\n\025Trans" +
+ "actionConfidence\0220\n\004type\030\001 \001(\0162\".wallet." +
+ "TransactionConfidence.Type\022\032\n\022appeared_a" +
+ "t_height\030\002 \001(\005\022\036\n\026overriding_transaction",
+ "\030\003 \001(\014\022\r\n\005depth\030\004 \001(\005\022\021\n\twork_done\030\005 \001(\003" +
+ "\022)\n\014broadcast_by\030\006 \003(\0132\023.wallet.PeerAddr" +
+ "ess\0224\n\006source\030\007 \001(\0162$.wallet.Transaction" +
+ "Confidence.Source\"Y\n\004Type\022\013\n\007UNKNOWN\020\000\022\014" +
+ "\n\010BUILDING\020\001\022\025\n\021NOT_SEEN_IN_CHAIN\020\002\022\025\n\021N" +
+ "OT_IN_BEST_CHAIN\020\003\022\010\n\004DEAD\020\004\"A\n\006Source\022\022" +
+ "\n\016SOURCE_UNKNOWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017" +
+ "\n\013SOURCE_SELF\020\002\"\211\003\n\013Transaction\022\017\n\007versi" +
+ "on\030\001 \002(\005\022\014\n\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.w" +
+ "allet.Transaction.Pool\022\021\n\tlock_time\030\004 \001(",
+ "\r\022\022\n\nupdated_at\030\005 \001(\003\0223\n\021transaction_inp" +
+ "ut\030\006 \003(\0132\030.wallet.TransactionInput\0225\n\022tr" +
+ "ansaction_output\030\007 \003(\0132\031.wallet.Transact" +
+ "ionOutput\022\022\n\nblock_hash\030\010 \003(\014\0221\n\nconfide" +
+ "nce\030\t \001(\0132\035.wallet.TransactionConfidence" +
+ "\"Y\n\004Pool\022\013\n\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INAC" +
+ "TIVE\020\002\022\010\n\004DEAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING" +
+ "_INACTIVE\020\022\"N\n\020ScryptParameters\022\014\n\004salt\030" +
+ "\001 \002(\014\022\020\n\001n\030\002 \001(\003:\00516384\022\014\n\001r\030\003 \001(\005:\0018\022\014\n" +
+ "\001p\030\004 \001(\005:\0011\"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004",
+ "data\030\002 \002(\014\022\021\n\tmandatory\030\003 \002(\010\"\255\003\n\006Wallet" +
+ "\022\032\n\022network_identifier\030\001 \002(\t\022\034\n\024last_see" +
+ "n_block_hash\030\002 \001(\014\022\036\n\026last_seen_block_he" +
+ "ight\030\014 \001(\r\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013" +
+ "transaction\030\004 \003(\0132\023.wallet.Transaction\022C" +
+ "\n\017encryption_type\030\005 \001(\0162\035.wallet.Wallet." +
+ "EncryptionType:\013UNENCRYPTED\0227\n\025encryptio" +
+ "n_parameters\030\006 \001(\0132\030.wallet.ScryptParame" +
+ "ters\022\017\n\007version\030\007 \001(\005\022$\n\textension\030\n \003(\013" +
+ "2\021.wallet.Extension\022\023\n\013description\030\013 \001(\t",
+ "\";\n\016EncryptionType\022\017\n\013UNENCRYPTED\020\001\022\030\n\024E" +
+ "NCRYPTED_SCRYPT_AES\020\002B\035\n\023org.bitcoinj.wa" +
+ "lletB\006Protos"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -6808,16 +8366,24 @@ public final class Protos {
new java.lang.String[] { "IpAddress", "Port", "Services", },
org.bitcoinj.wallet.Protos.PeerAddress.class,
org.bitcoinj.wallet.Protos.PeerAddress.Builder.class);
- internal_static_wallet_Key_descriptor =
+ internal_static_wallet_EncryptedPrivateKey_descriptor =
getDescriptor().getMessageTypes().get(1);
+ internal_static_wallet_EncryptedPrivateKey_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_wallet_EncryptedPrivateKey_descriptor,
+ new java.lang.String[] { "InitialisationVector", "EncryptedPrivateKey", },
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey.class,
+ org.bitcoinj.wallet.Protos.EncryptedPrivateKey.Builder.class);
+ internal_static_wallet_Key_descriptor =
+ getDescriptor().getMessageTypes().get(2);
internal_static_wallet_Key_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Key_descriptor,
- new java.lang.String[] { "Type", "PrivateKey", "PublicKey", "Label", "CreationTimestamp", },
+ new java.lang.String[] { "Type", "PrivateKey", "EncryptedPrivateKey", "PublicKey", "Label", "CreationTimestamp", },
org.bitcoinj.wallet.Protos.Key.class,
org.bitcoinj.wallet.Protos.Key.Builder.class);
internal_static_wallet_TransactionInput_descriptor =
- getDescriptor().getMessageTypes().get(2);
+ getDescriptor().getMessageTypes().get(3);
internal_static_wallet_TransactionInput_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_TransactionInput_descriptor,
@@ -6825,7 +8391,7 @@ public final class Protos {
org.bitcoinj.wallet.Protos.TransactionInput.class,
org.bitcoinj.wallet.Protos.TransactionInput.Builder.class);
internal_static_wallet_TransactionOutput_descriptor =
- getDescriptor().getMessageTypes().get(3);
+ getDescriptor().getMessageTypes().get(4);
internal_static_wallet_TransactionOutput_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_TransactionOutput_descriptor,
@@ -6833,7 +8399,7 @@ public final class Protos {
org.bitcoinj.wallet.Protos.TransactionOutput.class,
org.bitcoinj.wallet.Protos.TransactionOutput.Builder.class);
internal_static_wallet_TransactionConfidence_descriptor =
- getDescriptor().getMessageTypes().get(4);
+ getDescriptor().getMessageTypes().get(5);
internal_static_wallet_TransactionConfidence_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_TransactionConfidence_descriptor,
@@ -6841,15 +8407,23 @@ public final class Protos {
org.bitcoinj.wallet.Protos.TransactionConfidence.class,
org.bitcoinj.wallet.Protos.TransactionConfidence.Builder.class);
internal_static_wallet_Transaction_descriptor =
- getDescriptor().getMessageTypes().get(5);
+ getDescriptor().getMessageTypes().get(6);
internal_static_wallet_Transaction_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Transaction_descriptor,
new java.lang.String[] { "Version", "Hash", "Pool", "LockTime", "UpdatedAt", "TransactionInput", "TransactionOutput", "BlockHash", "Confidence", },
org.bitcoinj.wallet.Protos.Transaction.class,
org.bitcoinj.wallet.Protos.Transaction.Builder.class);
+ internal_static_wallet_ScryptParameters_descriptor =
+ getDescriptor().getMessageTypes().get(7);
+ internal_static_wallet_ScryptParameters_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_wallet_ScryptParameters_descriptor,
+ new java.lang.String[] { "Salt", "N", "R", "P", },
+ org.bitcoinj.wallet.Protos.ScryptParameters.class,
+ org.bitcoinj.wallet.Protos.ScryptParameters.Builder.class);
internal_static_wallet_Extension_descriptor =
- getDescriptor().getMessageTypes().get(6);
+ getDescriptor().getMessageTypes().get(8);
internal_static_wallet_Extension_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Extension_descriptor,
@@ -6857,11 +8431,11 @@ public final class Protos {
org.bitcoinj.wallet.Protos.Extension.class,
org.bitcoinj.wallet.Protos.Extension.Builder.class);
internal_static_wallet_Wallet_descriptor =
- getDescriptor().getMessageTypes().get(7);
+ getDescriptor().getMessageTypes().get(9);
internal_static_wallet_Wallet_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Wallet_descriptor,
- new java.lang.String[] { "NetworkIdentifier", "LastSeenBlockHash", "LastSeenBlockHeight", "Key", "Transaction", "Extension", },
+ new java.lang.String[] { "NetworkIdentifier", "LastSeenBlockHash", "LastSeenBlockHeight", "Key", "Transaction", "EncryptionType", "EncryptionParameters", "Version", "Extension", "Description", },
org.bitcoinj.wallet.Protos.Wallet.class,
org.bitcoinj.wallet.Protos.Wallet.Builder.class);
return null;
diff --git a/core/src/test/java/com/google/bitcoin/core/ECKeyTest.java b/core/src/test/java/com/google/bitcoin/core/ECKeyTest.java
index 7c8f89dc..4c61713b 100644
--- a/core/src/test/java/com/google/bitcoin/core/ECKeyTest.java
+++ b/core/src/test/java/com/google/bitcoin/core/ECKeyTest.java
@@ -16,19 +16,57 @@
package com.google.bitcoin.core;
-import org.junit.Test;
-import org.spongycastle.util.encoders.Hex;
+import static com.google.bitcoin.core.Utils.reverseBytes;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.math.BigInteger;
+import java.security.SecureRandom;
import java.security.SignatureException;
import java.util.Arrays;
-import static com.google.bitcoin.core.Utils.reverseBytes;
-import static org.junit.Assert.*;
+import org.bitcoinj.wallet.Protos;
+import org.bitcoinj.wallet.Protos.ScryptParameters;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.util.encoders.Hex;
+
+import com.google.bitcoin.crypto.EncryptedPrivateKey;
+import com.google.bitcoin.crypto.KeyCrypter;
+import com.google.bitcoin.crypto.KeyCrypterScrypt;
+import com.google.bitcoin.utils.BriefLogFormatter;
+import com.google.protobuf.ByteString;
public class ECKeyTest {
+ public Logger log = LoggerFactory.getLogger(ECKeyTest.class.getName());
+
+ private SecureRandom secureRandom;
+
+ private KeyCrypter keyCrypter;
+
+ private static CharSequence PASSWORD1 = "my hovercraft has eels";
+ private static CharSequence WRONG_PASSWORD = "it is a snowy day today";
+
+ @Before
+ public void setUp() throws Exception {
+ secureRandom = new SecureRandom();
+
+ byte[] salt = new byte[KeyCrypterScrypt.SALT_LENGTH];
+ secureRandom.nextBytes(salt);
+ Protos.ScryptParameters.Builder scryptParametersBuilder = Protos.ScryptParameters.newBuilder().setSalt(ByteString.copyFrom(salt));
+ ScryptParameters scryptParameters = scryptParametersBuilder.build();
+ keyCrypter = new KeyCrypterScrypt(scryptParameters);
+
+ BriefLogFormatter.init();
+ }
+
@Test
- public void testSignatures() {
+ public void testSignatures() throws Exception {
// Test that we can construct an ECKey from a private key (deriving the public from the private), then signing
// a message with it.
BigInteger privkey = new BigInteger(1, Hex.decode("180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"));
@@ -43,7 +81,7 @@ public class ECKeyTest {
}
@Test
- public void testASN1Roundtrip() {
+ public void testASN1Roundtrip() throws Exception {
byte[] privkeyASN1 = Hex.decode(
"3082011302010104205c0b98e524ad188ddef35dc6abba13c34a351a05409e5d285403718b93336a4aa081a53081a2020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101a144034200042af7a2aafe8dafd7dc7f9cfb58ce09bda7dce28653ab229b98d1d3d759660c672dd0db18c8c2d76aa470448e876fc2089ab1354c01a6e72cefc50915f4a963ee");
ECKey decodedKey = ECKey.fromASN1(privkeyASN1);
@@ -73,7 +111,7 @@ public class ECKeyTest {
}
@Test
- public void testKeyPairRoundtrip() {
+ public void testKeyPairRoundtrip() throws Exception {
byte[] privkeyASN1 = Hex.decode(
"3082011302010104205c0b98e524ad188ddef35dc6abba13c34a351a05409e5d285403718b93336a4aa081a53081a2020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101a144034200042af7a2aafe8dafd7dc7f9cfb58ce09bda7dce28653ab229b98d1d3d759660c672dd0db18c8c2d76aa470448e876fc2089ab1354c01a6e72cefc50915f4a963ee");
ECKey decodedKey = ECKey.fromASN1(privkeyASN1);
@@ -135,7 +173,7 @@ public class ECKeyTest {
ECKey key = new ECKey();
String message = "Hello World!";
String signatureBase64 = key.signMessage(message);
- System.out.println("Message signed with " + key.toAddress(NetworkParameters.prodNet()) + ": " + signatureBase64);
+ log.info("Message signed with " + key.toAddress(NetworkParameters.prodNet()) + ": " + signatureBase64);
// Should verify correctly.
key.verifyMessage(message, signatureBase64);
try {
@@ -176,6 +214,146 @@ public class ECKeyTest {
}
@Test
+ public void testUnencryptedCreate() throws Exception {
+ ECKey unencryptedKey = new ECKey();
+
+ // The key should initially be unencrypted.
+ assertTrue(!unencryptedKey.isEncrypted());
+
+ // Copy the private key bytes for checking later.
+ byte[] originalPrivateKeyBytes = new byte[32];
+ System.arraycopy(unencryptedKey.getPrivKeyBytes(), 0, originalPrivateKeyBytes, 0, 32);
+ log.info("Original private key = " + Utils.bytesToHexString(originalPrivateKeyBytes));
+
+ // Encrypt the key.
+ ECKey encryptedKey = unencryptedKey.encrypt(keyCrypter, keyCrypter.deriveKey(PASSWORD1));
+
+ // The key should now be encrypted.
+ assertTrue("Key is not encrypted but it should be", encryptedKey.isEncrypted());
+
+ // The unencrypted private key bytes of the encrypted keychain
+ // should be null or all be blank.
+ byte[] privateKeyBytes = encryptedKey.getPrivKeyBytes();
+ if (privateKeyBytes != null) {
+ for (int i = 0; i < privateKeyBytes.length; i++) {
+ assertEquals("Byte " + i + " of the private key was not zero but should be", 0, privateKeyBytes[i]);
+ }
+ }
+
+ // Decrypt the key.
+ unencryptedKey = encryptedKey.decrypt(keyCrypter, keyCrypter.deriveKey(PASSWORD1));
+
+ // The key should be unencrypted
+ assertTrue("Key is not unencrypted but it should be", !unencryptedKey.isEncrypted());
+
+ // The reborn unencrypted private key bytes should match the
+ // original private key.
+ privateKeyBytes = unencryptedKey.getPrivKeyBytes();
+ log.info("Reborn decrypted private key = " + Utils.bytesToHexString(privateKeyBytes));
+
+ for (int i = 0; i < privateKeyBytes.length; i++) {
+ assertEquals("Byte " + i + " of the private key did not match the original", originalPrivateKeyBytes[i],
+ privateKeyBytes[i]);
+ }
+ }
+
+ @Test
+ public void testEncryptedCreate() throws Exception {
+ ECKey unencryptedKey = new ECKey();
+
+ // Copy the private key bytes for checking later.
+ byte[] originalPrivateKeyBytes = new byte[32];
+ System.arraycopy(unencryptedKey.getPrivKeyBytes(), 0, originalPrivateKeyBytes, 0, 32);
+ log.info("Original private key = " + Utils.bytesToHexString(originalPrivateKeyBytes));
+
+ EncryptedPrivateKey encryptedPrivateKey = keyCrypter.encrypt(unencryptedKey.getPrivKeyBytes(), keyCrypter.deriveKey(PASSWORD1));
+ ECKey encryptedKey = new ECKey(encryptedPrivateKey, unencryptedKey.getPubKey(), keyCrypter);
+
+ // The key should initially be encrypted
+ assertTrue("Key not encrypted at start", encryptedKey.isEncrypted());
+
+ // The unencrypted private key bytes of the encrypted keychain should all be blank.
+ byte[] privateKeyBytes = encryptedKey.getPrivKeyBytes();
+ if (privateKeyBytes != null) {
+ for (int i = 0; i < privateKeyBytes.length; i++) {
+ assertEquals("Byte " + i + " of the private key was not zero but should be", 0, privateKeyBytes[i]);
+ }
+ }
+
+ // Decrypt the key.
+ ECKey rebornUnencryptedKey = encryptedKey.decrypt(keyCrypter, keyCrypter.deriveKey(PASSWORD1));
+
+ // The key should be unencrypted
+ assertTrue("Key is not unencrypted but it should be", !rebornUnencryptedKey.isEncrypted());
+
+ // The reborn unencrypted private key bytes should match the original private key.
+ privateKeyBytes = rebornUnencryptedKey.getPrivKeyBytes();
+ log.info("Reborn decrypted private key = " + Utils.bytesToHexString(privateKeyBytes));
+
+ for (int i = 0; i < privateKeyBytes.length; i++) {
+ assertEquals("Byte " + i + " of the private key did not match the original", originalPrivateKeyBytes[i], privateKeyBytes[i]);
+ }
+ }
+
+ @Test
+ public void testEncryptionIsReversible() throws Exception {
+ ECKey originalUnencryptedKey = new ECKey();
+ EncryptedPrivateKey encryptedPrivateKey = keyCrypter.encrypt(originalUnencryptedKey.getPrivKeyBytes(), keyCrypter.deriveKey(PASSWORD1));
+ ECKey encryptedKey = new ECKey(encryptedPrivateKey, originalUnencryptedKey.getPubKey(), keyCrypter);
+
+ // The key should be encrypted
+ assertTrue("Key not encrypted at start", encryptedKey.isEncrypted());
+
+ // Check that the key can be successfully decrypted back to the original.
+ assertTrue("Key encryption is not reversible but it should be", ECKey.encryptionIsReversible(originalUnencryptedKey, encryptedKey, keyCrypter, keyCrypter.deriveKey(PASSWORD1)));
+
+ // Check that key encryption is not reversible if a password other than the original is used to generate the AES key.
+ assertTrue("Key encryption is reversible with wrong password", !ECKey.encryptionIsReversible(originalUnencryptedKey, encryptedKey, keyCrypter, keyCrypter.deriveKey(WRONG_PASSWORD)));
+
+ // Change one of the encrypted key bytes (this is to simulate a faulty keyCrypter).
+ // Encryption should not be reversible
+ byte[] goodEncryptedPrivateKeyBytes = encryptedPrivateKey.getEncryptedBytes();
+
+ // Break the encrypted private key and check it is broken.
+ byte[] badEncryptedPrivateKeyBytes = goodEncryptedPrivateKeyBytes;
+
+ // XOR the 16th byte with 0x0A (this is fairly arbitary) to break it.
+ badEncryptedPrivateKeyBytes[16] = (byte) (badEncryptedPrivateKeyBytes[12] ^ new Byte("12").byteValue());
+
+ encryptedPrivateKey.setEncryptedPrivateBytes(badEncryptedPrivateKeyBytes);
+ ECKey badEncryptedKey = new ECKey(encryptedPrivateKey, originalUnencryptedKey.getPubKey(), keyCrypter);
+ assertTrue("Key encryption is reversible with faulty encrypted bytes", !ECKey.encryptionIsReversible(originalUnencryptedKey, badEncryptedKey, keyCrypter, keyCrypter.deriveKey(PASSWORD1)));
+ }
+
+ @Test
+ public void testToString() throws Exception {
+ ECKey key = new ECKey(BigInteger.TEN); // An example private key.
+
+ assertEquals("pub:04a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7893aba425419bc27a3b6c7e693a24c696f794c2ed877a1593cbee53b037368d7", key.toString());
+ assertEquals("pub:04a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7893aba425419bc27a3b6c7e693a24c696f794c2ed877a1593cbee53b037368d7 priv:0a", key.toStringWithPrivate());
+ }
+
+ @Test
+ public void keyRecoveryWithEncryptedKey() throws Exception {
+ ECKey unencryptedKey = new ECKey();
+ KeyParameter aesKey = keyCrypter.deriveKey(PASSWORD1);
+ ECKey encryptedKey = unencryptedKey.encrypt(keyCrypter,aesKey);
+
+ String message = "Goodbye Jupiter!";
+ Sha256Hash hash = Sha256Hash.create(message.getBytes());
+ ECKey.ECDSASignature sig = encryptedKey.sign(hash, aesKey);
+ unencryptedKey = new ECKey(null, unencryptedKey.getPubKey());
+ boolean found = false;
+ for (int i = 0; i < 4; i++) {
+ ECKey key2 = ECKey.recoverFromSignature(i, sig, hash, true);
+ if (unencryptedKey.equals(key2)) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found);
+ }
+
public void roundTripDumpedPrivKey() throws Exception {
ECKey key = new ECKey();
assertTrue(key.isCompressed());
@@ -186,4 +364,51 @@ public class ECKeyTest {
assertTrue(Arrays.equals(key.getPrivKeyBytes(), key2.getPrivKeyBytes()));
assertTrue(Arrays.equals(key.getPubKey(), key2.getPubKey()));
}
+
+ @Test
+ public void clear() throws Exception {
+ ECKey unencryptedKey = new ECKey();
+ ECKey encryptedKey = (new ECKey()).encrypt(keyCrypter, keyCrypter.deriveKey(PASSWORD1));
+
+ checkSomeBytesAreNonZero(unencryptedKey.getPrivKeyBytes());
+ unencryptedKey.clearPrivateKey();
+ checkAllBytesAreZero(unencryptedKey.getPrivKeyBytes());
+
+ // The encryptedPrivateKey should be null in an unencrypted ECKey anyhow but check all the same.
+ assertTrue(unencryptedKey.getEncryptedPrivateKey() == null);
+
+ checkSomeBytesAreNonZero(encryptedKey.getPrivKeyBytes());
+ checkSomeBytesAreNonZero(encryptedKey.getEncryptedPrivateKey().getEncryptedBytes());
+ checkSomeBytesAreNonZero(encryptedKey.getEncryptedPrivateKey().getInitialisationVector());
+ encryptedKey.clearPrivateKey();
+ checkAllBytesAreZero(encryptedKey.getPrivKeyBytes());
+ checkAllBytesAreZero(encryptedKey.getEncryptedPrivateKey().getEncryptedBytes());
+ checkAllBytesAreZero(encryptedKey.getEncryptedPrivateKey().getInitialisationVector());
+ }
+
+ private boolean checkSomeBytesAreNonZero(byte[] bytes) {
+ if (bytes == null) {
+ return false;
+ } else {
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private boolean checkAllBytesAreZero(byte[] bytes) {
+ if (bytes == null) {
+ return true;
+ } else {
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
}
diff --git a/core/src/test/java/com/google/bitcoin/core/FullBlockTestGenerator.java b/core/src/test/java/com/google/bitcoin/core/FullBlockTestGenerator.java
index cf866f40..3cd2a2ed 100644
--- a/core/src/test/java/com/google/bitcoin/core/FullBlockTestGenerator.java
+++ b/core/src/test/java/com/google/bitcoin/core/FullBlockTestGenerator.java
@@ -48,7 +48,7 @@ public class FullBlockTestGenerator {
coinbaseOutKeyPubKey = coinbaseOutKey.getPubKey();
Utils.rollMockClock(0); // Set a mock clock for timestamp tests
}
-
+
public List getBlocksToTest(boolean addExpensiveBlocks) throws ScriptException, ProtocolException, IOException {
List blocks = new LinkedList();
diff --git a/core/src/test/java/com/google/bitcoin/core/WalletTest.java b/core/src/test/java/com/google/bitcoin/core/WalletTest.java
index 8d18cb03..4aa08418 100644
--- a/core/src/test/java/com/google/bitcoin/core/WalletTest.java
+++ b/core/src/test/java/com/google/bitcoin/core/WalletTest.java
@@ -18,20 +18,33 @@ package com.google.bitcoin.core;
import com.google.bitcoin.core.Transaction.SigHash;
import com.google.bitcoin.core.WalletTransaction.Pool;
+import com.google.bitcoin.crypto.KeyCrypter;
+import com.google.bitcoin.crypto.KeyCrypterException;
+import com.google.bitcoin.crypto.KeyCrypterScrypt;
import com.google.bitcoin.store.BlockStore;
import com.google.bitcoin.store.MemoryBlockStore;
import com.google.bitcoin.utils.BriefLogFormatter;
import com.google.bitcoin.utils.Locks;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.CycleDetectingLockFactory;
+import com.google.protobuf.ByteString;
+
+import org.bitcoinj.wallet.Protos;
+import org.bitcoinj.wallet.Protos.ScryptParameters;
+import org.bitcoinj.wallet.Protos.Wallet.EncryptionType;
import org.junit.Before;
import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.spongycastle.crypto.params.KeyParameter;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
+import java.security.SecureRandom;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
@@ -45,26 +58,74 @@ import static com.google.bitcoin.core.Utils.toNanoCoins;
import static org.junit.Assert.*;
public class WalletTest {
+ public Logger log = LoggerFactory.getLogger(WalletTest.class.getName());
+
static final NetworkParameters params = NetworkParameters.unitTests();
private Address myAddress;
+ private Address myEncryptedAddress;
+ private Address myEncryptedAddress2;
+
private Wallet wallet;
+ private Wallet encryptedWallet;
+ // A wallet with an initial unencrypted private key and an encrypted private key.
+ private Wallet encryptedHetergeneousWallet;
+
private BlockChain chain;
private BlockStore blockStore;
private ECKey myKey;
+ private ECKey myEncryptedKey;
+
+ private ECKey myKey2;
+ private ECKey myEncryptedKey2;
+
+ private static CharSequence PASSWORD1 = "my helicopter contains eels";
+ private static CharSequence WRONG_PASSWORD = "nothing noone nobody nowhere";
+
+ private KeyParameter aesKey;
+ private KeyParameter wrongAesKey;
+
+ private KeyCrypter keyCrypter;
+
+ private SecureRandom secureRandom = new SecureRandom();
@Before
public void setUp() throws Exception {
myKey = new ECKey();
+ myKey2 = new ECKey();
myAddress = myKey.toAddress(params);
wallet = new Wallet(params);
wallet.addKey(myKey);
+
+ byte[] salt = new byte[KeyCrypterScrypt.SALT_LENGTH];
+ secureRandom.nextBytes(salt);
+ Protos.ScryptParameters.Builder scryptParametersBuilder = Protos.ScryptParameters.newBuilder().setSalt(ByteString.copyFrom(salt));
+ ScryptParameters scryptParameters = scryptParametersBuilder.build();
+
+ keyCrypter = new KeyCrypterScrypt(scryptParameters);
+
+ wallet = new Wallet(params);
+ encryptedWallet = new Wallet(params, keyCrypter);
+ encryptedHetergeneousWallet = new Wallet(params, keyCrypter);
+
+ aesKey = keyCrypter.deriveKey(PASSWORD1);
+ wrongAesKey = keyCrypter.deriveKey(WRONG_PASSWORD);
+
+ wallet.addKey(myKey);
+
+ myEncryptedKey = encryptedWallet.addNewEncryptedKey(keyCrypter, aesKey);
+ myEncryptedAddress = myEncryptedKey.toAddress(params);
+
+ encryptedHetergeneousWallet.addKey(myKey2);
+ myEncryptedKey2 = encryptedHetergeneousWallet.addNewEncryptedKey(keyCrypter, aesKey);
+ myEncryptedAddress2 = myEncryptedKey2.toAddress(params);
+
blockStore = new MemoryBlockStore(params);
chain = new BlockChain(params, wallet, blockStore);
BriefLogFormatter.init();
}
- private Transaction sendMoneyToWallet(Transaction tx, AbstractBlockChain.NewBlockType type)
+ private Transaction sendMoneyToWallet(Wallet wallet, Transaction tx, AbstractBlockChain.NewBlockType type)
throws IOException, ProtocolException, VerificationException {
if (type == null) {
// Pending/broadcast tx.
@@ -79,53 +140,133 @@ public class WalletTest {
return tx;
}
- private Transaction sendMoneyToWallet(BigInteger value, AbstractBlockChain.NewBlockType type)
+ private Transaction sendMoneyToWallet(Transaction tx, AbstractBlockChain.NewBlockType type) throws IOException,
+ ProtocolException, VerificationException {
+ return sendMoneyToWallet(this.wallet, tx, type);
+ }
+
+ private Transaction sendMoneyToWallet(Wallet wallet, BigInteger value, Address toAddress, AbstractBlockChain.NewBlockType type)
throws IOException, ProtocolException, VerificationException {
- return sendMoneyToWallet(createFakeTx(params, value, myAddress), type);
+ return sendMoneyToWallet(wallet, createFakeTx(params, value, toAddress), type);
+ }
+
+ private Transaction sendMoneyToWallet(BigInteger value, AbstractBlockChain.NewBlockType type) throws IOException,
+ ProtocolException, VerificationException {
+ return sendMoneyToWallet(this.wallet, createFakeTx(params, value, myAddress), type);
}
@Test
public void basicSpending() throws Exception {
- // We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change. We
- // will attach a small fee. Because the Bitcoin protocol makes it difficult to determine the fee of an
- // arbitrary transaction in isolation, we'll check that the fee was set by examining the size of the change.
+ basicSpendingCommon(wallet, myAddress, false);
+ }
+
+ @Test
+ public void basicSpendingWithEncryptedWallet() throws Exception {
+ basicSpendingCommon(encryptedWallet, myEncryptedAddress, true);
+ }
+
+ @Test
+ public void basicSpendingWithEncryptedHetergeneousWallet() throws Exception {
+ basicSpendingCommon(encryptedHetergeneousWallet, myEncryptedAddress2, true);
+ }
+
+ private void basicSpendingCommon(Wallet wallet, Address toAddress, boolean testEncryption) throws Exception {
+ // We'll set up a wallet that receives a coin, then sends a coin of
+ // lesser value and keeps the change. We
+ // will attach a small fee. Because the Bitcoin protocol makes it
+ // difficult to determine the fee of an
+ // arbitrary transaction in isolation, we'll check that the fee was set
+ // by examining the size of the change.
// Receive some money as a pending transaction.
- BigInteger v1 = Utils.toNanoCoins(1, 0);
- Transaction t1 = sendMoneyToWallet(v1, null);
- assertEquals(BigInteger.ZERO, wallet.getBalance());
- assertEquals(v1, wallet.getBalance(Wallet.BalanceType.ESTIMATED));
- assertEquals(1, wallet.getPoolSize(Pool.PENDING));
- assertEquals(0, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
- sendMoneyToWallet(t1, AbstractBlockChain.NewBlockType.BEST_CHAIN);
- assertEquals(v1, wallet.getBalance());
- assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
- assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
+ receiveAPendingTransaction(wallet, toAddress);
- // Create a send with a fee.
+ // Prepare to send.
Address destination = new ECKey().toAddress(params);
BigInteger v2 = toNanoCoins(0, 50);
Wallet.SendRequest req = Wallet.SendRequest.to(destination, v2);
req.fee = toNanoCoins(0, 1);
+
+ if (testEncryption) {
+ // Try to create a send with a fee but no password (this should fail).
+ try {
+ wallet.completeTx(req);
+ fail("No exception was thrown trying to sign an encrypted key with no password supplied.");
+ } catch (KeyCrypterException kce) {
+ assertEquals("This ECKey is encrypted but no decryption key has been supplied.", kce.getMessage());
+ }
+ assertEquals("Wrong number of UNSPENT.1", 1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
+ assertEquals("Wrong number of ALL.1", 1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
+
+ // Try to create a send with a fee but the wrong password (this should fail).
+ req = Wallet.SendRequest.to(destination, v2);
+ req.aesKey = wrongAesKey;
+ req.fee = toNanoCoins(0, 1);
+
+ try {
+ wallet.completeTx(req);
+ fail("No exception was thrown trying to sign an encrypted key with the wrong password supplied.");
+ } catch (KeyCrypterException kce) {
+ assertEquals("Could not decrypt bytes", kce.getMessage());
+ }
+
+ assertEquals("Wrong number of UNSPENT.2", 1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
+ assertEquals("Wrong number of ALL.2", 1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
+
+ // Create a send with a fee with the correct password (this should succeed).
+ req = Wallet.SendRequest.to(destination, v2);
+ req.aesKey = aesKey;
+ req.fee = toNanoCoins(0, 1);
+ }
+
+ // Complete the transaction successfully.
wallet.completeTx(req);
+
Transaction t2 = req.tx;
- assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
- assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
+ assertEquals("Wrong number of UNSPENT.3", 1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
+ assertEquals("Wrong number of ALL.3", 1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
assertEquals(TransactionConfidence.Source.SELF, t2.getConfidence().getSource());
assertEquals(wallet.getChangeAddress(), t2.getOutput(1).getScriptPubKey().getToAddress());
// Do some basic sanity checks.
- assertEquals(1, t2.getInputs().size());
- assertEquals(myAddress, t2.getInputs().get(0).getScriptSig().getFromAddress());
- assertEquals(t2.getConfidence().getConfidenceType(), TransactionConfidence.ConfidenceType.NOT_SEEN_IN_CHAIN);
- assertEquals(2, t2.getOutputs().size());
- assertEquals(destination, t2.getOutputs().get(0).getScriptPubKey().getToAddress());
- assertEquals(wallet.getChangeAddress(), t2.getOutputs().get(1).getScriptPubKey().getToAddress());
- BigInteger v3 = toNanoCoins(0, 49);
- assertEquals(v3, t2.getOutputs().get(1).getValue());
- // Check the script runs and signatures verify.
- t2.getInputs().get(0).verify();
+ basicSanityChecks(wallet, t2, toAddress, destination);
+ // Broadcast the transaction and commit.
+ broadcastAndCommit(wallet, t2);
+
+ // Now check that we can spend the unconfirmed change, with a new change
+ // address of our own selection.
+ // (req.aesKey is null for unencrypted / the correct aesKey for encrypted.)
+ spendUnconfirmedChange(wallet, t2, req.aesKey);
+ }
+
+ private void receiveAPendingTransaction(Wallet wallet, Address toAddress) throws Exception {
+ BigInteger v1 = Utils.toNanoCoins(1, 0);
+ Transaction t1 = sendMoneyToWallet(wallet, v1, toAddress, null);
+ assertEquals(BigInteger.ZERO, wallet.getBalance());
+ assertEquals(v1, wallet.getBalance(Wallet.BalanceType.ESTIMATED));
+ assertEquals(1, wallet.getPoolSize(Pool.PENDING));
+ assertEquals(0, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
+ sendMoneyToWallet(wallet, t1, AbstractBlockChain.NewBlockType.BEST_CHAIN);
+ assertEquals("Incorrect confirmed tx balance", v1, wallet.getBalance());
+ assertEquals("Incorrect confirmed tx PENDING pool size", 0, wallet.getPoolSize(WalletTransaction.Pool.PENDING));
+ assertEquals("Incorrect confirmed tx UNSPENT pool size", 1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
+ assertEquals("Incorrect confirmed tx ALL pool size", 1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
+ }
+
+ private void basicSanityChecks(Wallet wallet, Transaction t, Address fromAddress, Address destination) throws ScriptException {
+ assertEquals("Wrong number of tx inputs", 1, t.getInputs().size());
+ assertEquals(fromAddress, t.getInputs().get(0).getScriptSig().getFromAddress());
+ assertEquals(t.getConfidence().getConfidenceType(), TransactionConfidence.ConfidenceType.NOT_SEEN_IN_CHAIN);
+ assertEquals("Wrong number of tx outputs",2, t.getOutputs().size());
+ assertEquals(destination, t.getOutputs().get(0).getScriptPubKey().getToAddress());
+ assertEquals(wallet.getChangeAddress(), t.getOutputs().get(1).getScriptPubKey().getToAddress());
+ assertEquals(toNanoCoins(0, 49), t.getOutputs().get(1).getValue());
+ // Check the script runs and signatures verify.
+ t.getInputs().get(0).verify();
+ }
+
+ private void broadcastAndCommit(Wallet wallet, Transaction t) throws Exception {
final LinkedList txns = Lists.newLinkedList();
wallet.addEventListener(new AbstractWalletEventListener() {
@Override
@@ -133,19 +274,22 @@ public class WalletTest {
txns.add(tx);
}
});
- // We broadcast the TX over the network, and then commit to it.
- t2.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByAddress(new byte[]{1,2,3,4})));
- t2.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByAddress(new byte[]{10,2,3,4})));
- wallet.commitTx(t2);
+
+ t.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByAddress(new byte[]{1,2,3,4})));
+ t.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByAddress(new byte[]{10,2,3,4})));
+ wallet.commitTx(t);
assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.PENDING));
assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.SPENT));
assertEquals(2, wallet.getPoolSize(WalletTransaction.Pool.ALL));
- assertEquals(t2, txns.getFirst());
+ assertEquals(t, txns.getFirst());
assertEquals(1, txns.size());
+ }
- // Now check that we can spend the unconfirmed change, with a new change address of our own selection.
+ private void spendUnconfirmedChange(Wallet wallet, Transaction t2, KeyParameter aesKey) throws Exception {
+ BigInteger v3 = toNanoCoins(0, 49);
assertEquals(v3, wallet.getBalance());
- req = Wallet.SendRequest.to(new ECKey().toAddress(params), toNanoCoins(0, 48));
+ Wallet.SendRequest req = Wallet.SendRequest.to(new ECKey().toAddress(params), toNanoCoins(0, 48));
+ req.aesKey = aesKey;
Address a = req.changeAddress = new ECKey().toAddress(params);
wallet.completeTx(req);
Transaction t3 = req.tx;
@@ -153,7 +297,7 @@ public class WalletTest {
assertNotNull(t3);
wallet.commitTx(t3);
assertTrue(wallet.isConsistent());
- // t2 and t3 gets confirmed in the same block.
+ // t2 and t3 gets confirmed in the same block.
BlockPair bp = createFakeBlock(blockStore, t2, t3);
wallet.receiveFromBlock(t2, bp.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN);
wallet.receiveFromBlock(t3, bp.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN);
@@ -340,12 +484,12 @@ public class WalletTest {
tx.addOutput(output);
wallet.receiveFromBlock(tx, null, BlockChain.NewBlockType.BEST_CHAIN);
- assertTrue(wallet.isConsistent());
+ assertTrue("Wallet is not consistent", wallet.isConsistent());
Transaction txClone = new Transaction(params, tx.bitcoinSerialize());
try {
wallet.receiveFromBlock(txClone, null, BlockChain.NewBlockType.BEST_CHAIN);
- fail();
+ fail("Illegal argument not thrown when it should have been.");
} catch (IllegalStateException ex) {
// expected
}
@@ -751,7 +895,7 @@ public class WalletTest {
// TODO: This code is messy, improve the Script class and fixinate!
assertEquals(t2.toString(), 1, t2.getInputs().get(0).getScriptSig().chunks.size());
assertTrue(t2.getInputs().get(0).getScriptSig().chunks.get(0).data.length > 50);
- System.out.println(t2);
+ log.info(t2.toString(chain));
}
@Test
@@ -764,23 +908,23 @@ public class WalletTest {
ECKey key = new ECKey();
wallet.addKey(key);
Sha256Hash hash2 = Sha256Hash.hashFileContents(f);
- assertFalse(hash1.equals(hash2)); // File has changed.
+ assertFalse("Wallet not saved after addKey", hash1.equals(hash2)); // File has changed.
Transaction t1 = createFakeTx(params, toNanoCoins(5, 0), key);
if (wallet.isPendingTransactionRelevant(t1))
wallet.receivePending(t1, null);
Sha256Hash hash3 = Sha256Hash.hashFileContents(f);
- assertFalse(hash2.equals(hash3)); // File has changed again.
+ assertFalse("Wallet not saved after receivePending", hash2.equals(hash3)); // File has changed again.
Block b1 = createFakeBlock(blockStore, t1).block;
chain.add(b1);
Sha256Hash hash4 = Sha256Hash.hashFileContents(f);
- assertFalse(hash3.equals(hash4)); // File has changed again.
+ assertFalse("Wallet not saved after chain add.1", hash3.equals(hash4)); // File has changed again.
// Check that receiving some block without any relevant transactions still triggers a save.
Block b2 = b1.createNextBlock(new ECKey().toAddress(params));
chain.add(b2);
- assertFalse(hash4.equals(Sha256Hash.hashFileContents(f))); // File has changed again.
+ assertFalse("Wallet not saved after chain add.2", hash4.equals(Sha256Hash.hashFileContents(f))); // File has changed again.
}
@Test
@@ -846,7 +990,7 @@ public class WalletTest {
@Test
public void spendOutputFromPendingTransaction() throws Exception {
- // We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change.
+ // We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change.
BigInteger v1 = Utils.toNanoCoins(1, 0);
sendMoneyToWallet(v1, AbstractBlockChain.NewBlockType.BEST_CHAIN);
// First create our current transaction
@@ -884,6 +1028,127 @@ public class WalletTest {
}
@Test
+ public void encryptionDecryptionBasic() throws Exception {
+ encryptionDecryptionBasicCommon(encryptedWallet);
+ encryptionDecryptionBasicCommon(encryptedHetergeneousWallet);
+ }
+
+ private void encryptionDecryptionBasicCommon(Wallet wallet) {
+ // Check the wallet is initially of WalletType ENCRYPTED.
+ assertTrue("Wallet is not an encrypted wallet", wallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES);
+
+ // Correct password should decrypt first encrypted private key.
+ assertTrue("checkPasswordCanDecryptFirstPrivateKey result is wrong with correct password.2", wallet.checkPassword(PASSWORD1));
+
+ // Incorrect password should not decrypt first encrypted private key.
+ assertTrue("checkPasswordCanDecryptFirstPrivateKey result is wrong with incorrect password.3", !wallet.checkPassword(WRONG_PASSWORD));
+
+ // Decrypt wallet.
+ assertTrue("The keyCrypter is missing but should not be", keyCrypter != null);
+ wallet.decrypt(aesKey);
+
+ // Wallet should now be unencrypted.
+ assertTrue("Wallet is not an unencrypted wallet", wallet.getKeyCrypter() == null);
+
+ // Correct password should not decrypt first encrypted private key as wallet is unencrypted.
+ assertTrue("checkPasswordCanDecryptFirstPrivateKey result is wrong with correct password", !wallet.checkPassword(PASSWORD1));
+
+ // Incorrect password should not decrypt first encrypted private key as wallet is unencrypted.
+ assertTrue("checkPasswordCanDecryptFirstPrivateKey result is wrong with incorrect password", !wallet.checkPassword(WRONG_PASSWORD));
+
+ // Encrypt wallet.
+ wallet.encrypt(keyCrypter, aesKey);
+
+ // Wallet should now be of type WalletType.ENCRYPTED_SCRYPT_AES.
+ assertTrue("Wallet is not an encrypted wallet", wallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES);
+ }
+
+ @Test
+ public void encryptionDecryptionBadPassword() throws Exception {
+ // Check the wallet is currently encrypted
+ assertTrue("Wallet is not an encrypted wallet", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES);
+
+ // Chek that the wrong password does not decrypt the wallet.
+ try {
+ encryptedWallet.decrypt(wrongAesKey);
+ fail("Incorrectly decoded wallet with wrong password");
+ } catch (KeyCrypterException ede) {
+ assertTrue("Wrong message in EncrypterDecrypterException", ede.getMessage().indexOf("Could not decrypt bytes") > -1);
+ }
+ }
+
+ @Test
+ public void encryptionDecryptionCheckExceptions() throws Exception {
+ // Check the wallet is currently encrypted
+ assertTrue("Wallet is not an encrypted wallet", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES);
+
+ // Decrypt wallet.
+ assertTrue("The keyCrypter is missing but should not be.1", keyCrypter != null);
+ encryptedWallet.decrypt(aesKey);
+
+ // Try decrypting it again
+ try {
+ assertTrue("The keyCrypter is missing but should not be.2", keyCrypter != null);
+ encryptedWallet.decrypt(aesKey);
+ fail("Should not be able to decrypt a decrypted wallet");
+ } catch (IllegalStateException e) {
+ assertTrue("Expected behaviour", true);
+ }
+ assertTrue("Wallet is not an unencrypted wallet.2", encryptedWallet.getKeyCrypter() == null);
+
+ // Encrypt wallet.
+ encryptedWallet.encrypt(keyCrypter, aesKey);
+
+ assertTrue("Wallet is not an encrypted wallet.2", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES);
+
+ // Try encrypting it again
+ try {
+ encryptedWallet.encrypt(keyCrypter, aesKey);
+ fail("Should not be able to encrypt an encrypted wallet");
+ } catch (IllegalStateException e) {
+ assertTrue("Expected behaviour", true);
+ }
+ assertTrue("Wallet is not an encrypted wallet.3", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES);
+ }
+
+ @Test
+ public void encryptionDecryptionHomogenousKeys() throws Exception {
+ // Check the wallet is currently encrypted
+ assertTrue("Wallet is not an encrypted wallet", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES);
+
+ // Try added an ECKey that was encrypted with a differenct ScryptParameters (i.e. a non-homogenous key).
+ // This is not allowed as the ScryptParameters is stored at the Wallet level.
+ byte[] salt = new byte[KeyCrypterScrypt.SALT_LENGTH];
+ secureRandom.nextBytes(salt);
+ Protos.ScryptParameters.Builder scryptParametersBuilder = Protos.ScryptParameters.newBuilder().setSalt(ByteString.copyFrom(salt));
+ ScryptParameters scryptParameters = scryptParametersBuilder.build();
+
+ KeyCrypter keyCrypterDifferent = new KeyCrypterScrypt(scryptParameters);
+
+ ECKey ecKeyDifferent = new ECKey();
+ ecKeyDifferent = ecKeyDifferent.encrypt(keyCrypterDifferent, aesKey);
+
+ Iterable keys = encryptedWallet.getKeys();
+ Iterator iterator = keys.iterator();
+ boolean oneKey = iterator.hasNext();
+ iterator.next();
+ assertTrue("Wrong number of keys in wallet before key addition", oneKey && !iterator.hasNext());
+
+ try {
+ encryptedWallet.addKey(ecKeyDifferent);
+ fail("AddKey should have thrown an EncrypterDecrypterException but did not.");
+ } catch (KeyCrypterException ede) {
+ // Expected behaviour.
+ }
+
+ keys = encryptedWallet.getKeys();
+ iterator = keys.iterator();
+ oneKey = iterator.hasNext();
+
+ iterator.next();
+ assertTrue("Wrong number of keys in wallet after key addition", oneKey && !iterator.hasNext());
+ }
+
public void ageMattersDuringSelection() throws Exception {
// Test that we prefer older coins to newer coins when building spends. This reduces required fees and improves
// time to confirmation as the transaction will appear less spammy.
diff --git a/core/src/test/java/com/google/bitcoin/crypto/KeyCrypterScryptTest.java b/core/src/test/java/com/google/bitcoin/crypto/KeyCrypterScryptTest.java
new file mode 100644
index 00000000..5e72f8bf
--- /dev/null
+++ b/core/src/test/java/com/google/bitcoin/crypto/KeyCrypterScryptTest.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright 2013 Jim Burton.
+ *
+ * Licensed under the MIT license (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://opensource.org/licenses/mit-license.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.bitcoin.crypto;
+
+import java.io.UnsupportedEncodingException;
+import java.security.SecureRandom;
+import java.util.Random;
+import java.util.UUID;
+
+import junit.framework.TestCase;
+
+import org.bitcoinj.wallet.Protos;
+import org.bitcoinj.wallet.Protos.ScryptParameters;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.bitcoin.core.Utils;
+import com.google.bitcoin.utils.BriefLogFormatter;
+import com.google.protobuf.ByteString;
+
+public class KeyCrypterScryptTest extends TestCase {
+
+ private static final Logger log = LoggerFactory.getLogger(KeyCrypterScryptTest.class);
+
+ // Nonsense bytes for encryption test.
+ private static final byte[] TEST_BYTES1 = new byte[]{0, -101, 2, 103, -4, 105, 6, 107, 8, -109, 10, 111, -12, 113, 14, -115, 16, 117, -18, 119, 20, 121, 22, 123, -24, 125, 26, 127, -28, 29, -30, 31};
+
+ private static CharSequence PASSWORD1 = "aTestPassword";
+ private static CharSequence PASSWORD2 = "0123456789";
+
+ private static CharSequence WRONG_PASSWORD = "thisIsTheWrongPassword";
+
+ private SecureRandom secureRandom;
+ private ScryptParameters scryptParameters;
+
+ @Before
+ public void setUp() throws Exception {
+ secureRandom = new SecureRandom();
+
+ byte[] salt = new byte[KeyCrypterScrypt.SALT_LENGTH];
+ secureRandom.nextBytes(salt);
+ Protos.ScryptParameters.Builder scryptParametersBuilder = Protos.ScryptParameters.newBuilder().setSalt(ByteString.copyFrom(salt));
+ scryptParameters = scryptParametersBuilder.build();
+
+ BriefLogFormatter.init();
+ }
+
+ @Test
+ public void testKeyCrypterGood1() throws KeyCrypterException {
+ KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);
+
+ // Encrypt.
+ EncryptedPrivateKey encryptedPrivateKey = keyCrypter.encrypt(TEST_BYTES1, keyCrypter.deriveKey(PASSWORD1));
+ assertNotNull(encryptedPrivateKey);
+
+ // Decrypt.
+ byte[] reborn = keyCrypter.decrypt(encryptedPrivateKey, keyCrypter.deriveKey(PASSWORD1));
+ log.debug("Original: " + Utils.bytesToHexString(TEST_BYTES1));
+ log.debug("Reborn : " + Utils.bytesToHexString(reborn));
+ assertEquals(Utils.bytesToHexString(TEST_BYTES1), Utils.bytesToHexString(reborn));
+ }
+
+ /**
+ * Test with random plain text strings and random passwords.
+ * UUIDs are used and hence will only cover hex characters (and the separator hyphen).
+ * @throws KeyCrypterException
+ * @throws UnsupportedEncodingException
+ */
+ public void testKeyCrypterGood2() throws KeyCrypterException, UnsupportedEncodingException {
+ KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);
+
+ int numberOfTests = 16;
+ System.out.print("EncrypterDecrypterTest: Trying random UUIDs for plainText and passwords :");
+ for (int i = 0; i < numberOfTests; i++) {
+ // Create a UUID as the plaintext and use another for the password.
+ String plainText = UUID.randomUUID().toString();
+ CharSequence password = UUID.randomUUID().toString();
+
+ EncryptedPrivateKey encryptedPrivateKey = keyCrypter.encrypt(plainText.getBytes(), keyCrypter.deriveKey(password));
+
+ assertNotNull(encryptedPrivateKey);
+
+ byte[] reconstructedPlainBytes = keyCrypter.decrypt(encryptedPrivateKey,keyCrypter.deriveKey(password));
+ assertEquals(Utils.bytesToHexString(plainText.getBytes()), Utils.bytesToHexString(reconstructedPlainBytes));
+ System.out.print('.');
+ }
+ System.out.println(" Done.");
+ }
+
+ public void testKeyCrypterWrongPassword() throws KeyCrypterException {
+ KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);
+
+ // create a longer encryption string
+ StringBuffer stringBuffer = new StringBuffer();
+ for (int i = 0; i < 100; i++) {
+ stringBuffer.append(i + " ").append("The quick brown fox");
+ }
+
+ EncryptedPrivateKey encryptedPrivateKey = keyCrypter.encrypt(stringBuffer.toString().getBytes(), keyCrypter.deriveKey(PASSWORD2));
+ assertNotNull(encryptedPrivateKey);
+
+ try {
+ keyCrypter.decrypt(encryptedPrivateKey, keyCrypter.deriveKey(WRONG_PASSWORD));
+ fail("Decrypt with wrong password did not throw exception");
+ } catch (KeyCrypterException ede) {
+ assertTrue(ede.getMessage().indexOf("Could not decrypt") > -1);
+ }
+ }
+
+ @Test
+ public void testEncryptDecryptBytes1() throws KeyCrypterException {
+ KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);
+
+ // Encrypt bytes.
+ EncryptedPrivateKey encryptedPrivateKey = keyCrypter.encrypt(TEST_BYTES1, keyCrypter.deriveKey(PASSWORD1));
+ assertNotNull(encryptedPrivateKey);
+ log.debug("\nEncrypterDecrypterTest: cipherBytes = \nlength = " + encryptedPrivateKey.getEncryptedBytes().length + "\n---------------\n" + Utils.bytesToHexString(encryptedPrivateKey.getEncryptedBytes()) + "\n---------------\n");
+
+ byte[] rebornPlainBytes = keyCrypter.decrypt(encryptedPrivateKey, keyCrypter.deriveKey(PASSWORD1));
+
+ log.debug("Original: " + Utils.bytesToHexString(TEST_BYTES1));
+ log.debug("Reborn1 : " + Utils.bytesToHexString(rebornPlainBytes));
+ assertEquals( Utils.bytesToHexString(TEST_BYTES1), Utils.bytesToHexString(rebornPlainBytes));
+ }
+
+ @Test
+ public void testEncryptDecryptBytes2() throws KeyCrypterException {
+ KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(scryptParameters);
+
+ // Encrypt random bytes of various lengths up to length 50.
+ Random random = new Random();
+
+ for (int i = 0; i < 50; i++) {
+ byte[] plainBytes = new byte[i];
+ random.nextBytes(plainBytes);
+
+ EncryptedPrivateKey encryptedPrivateKey = keyCrypter.encrypt(plainBytes, keyCrypter.deriveKey(PASSWORD1));
+ assertNotNull(encryptedPrivateKey);
+ //log.debug("\nEncrypterDecrypterTest: cipherBytes = \nlength = " + cipherBytes.length + "\n---------------\n" + Utils.bytesToHexString(cipherBytes) + "\n---------------\n");
+
+ byte[] rebornPlainBytes = keyCrypter.decrypt(encryptedPrivateKey, keyCrypter.deriveKey(PASSWORD1));
+
+ log.debug("Original: (" + i + ") " + Utils.bytesToHexString(plainBytes));
+ log.debug("Reborn1 : (" + i + ") " + Utils.bytesToHexString(rebornPlainBytes));
+ assertEquals( Utils.bytesToHexString(plainBytes), Utils.bytesToHexString(rebornPlainBytes));
+ }
+ }
+}
diff --git a/core/src/test/java/com/google/bitcoin/store/WalletProtobufSerializerTest.java b/core/src/test/java/com/google/bitcoin/store/WalletProtobufSerializerTest.java
index 5f34d265..321572ce 100644
--- a/core/src/test/java/com/google/bitcoin/store/WalletProtobufSerializerTest.java
+++ b/core/src/test/java/com/google/bitcoin/store/WalletProtobufSerializerTest.java
@@ -6,6 +6,7 @@ import com.google.bitcoin.core.TransactionConfidence.ConfidenceType;
import com.google.bitcoin.utils.BriefLogFormatter;
import com.google.protobuf.ByteString;
import org.bitcoinj.wallet.Protos;
+import org.bitcoinj.wallet.Protos.Wallet.EncryptionType;
import org.junit.Before;
import org.junit.Test;
@@ -19,12 +20,16 @@ import java.util.*;
import static com.google.bitcoin.core.TestUtils.createFakeTx;
import static org.junit.Assert.*;
+import com.google.bitcoin.crypto.KeyCrypter;
+
public class WalletProtobufSerializerTest {
static final NetworkParameters params = NetworkParameters.unitTests();
private ECKey myKey;
private Address myAddress;
private Wallet myWallet;
+ public static String WALLET_DESCRIPTION = "The quick brown fox lives in \u4f26\u6566"; // Beijing in Chinese
+
@Before
public void setUp() throws Exception {
BriefLogFormatter.initVerbose();
@@ -33,6 +38,7 @@ public class WalletProtobufSerializerTest {
myAddress = myKey.toAddress(params);
myWallet = new Wallet(params);
myWallet.addKey(myKey);
+ myWallet.setDescription(WALLET_DESCRIPTION);
}
@Test
@@ -47,6 +53,7 @@ public class WalletProtobufSerializerTest {
wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getPrivKeyBytes());
assertEquals(myKey.getCreationTimeSeconds(),
wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getCreationTimeSeconds());
+ assertEquals(WALLET_DESCRIPTION, wallet1.getDescription());
}
@Test
@@ -220,7 +227,7 @@ public class WalletProtobufSerializerTest {
assertEquals(work2, rebornConfidence1.getWorkDone());
}
- private Wallet roundTrip(Wallet wallet) throws IOException {
+ private Wallet roundTrip(Wallet wallet) throws Exception {
ByteArrayOutputStream output = new ByteArrayOutputStream();
//System.out.println(WalletProtobufSerializer.walletToText(wallet));
new WalletProtobufSerializer().writeWallet(wallet, output);
@@ -252,14 +259,14 @@ public class WalletProtobufSerializerTest {
rnd.nextBytes(wallet1.random_bytes);
Wallet wallet2 = roundTripExtension(wallet1);
- assertTrue(wallet2 instanceof WalletExtension);
+ assertTrue("Wallet2 is not an instance of WalletExtension. It is a " + wallet2.getClass().getCanonicalName(), wallet2 instanceof WalletExtension);
WalletExtension wallet2ext = (WalletExtension)wallet2;
- assertNotNull(wallet2ext.random_bytes);
+ assertNotNull("Wallet2s random bytes were null", wallet2ext.random_bytes);
for (int i = 0; i < 100; i++) {
- assertEquals(wallet1.random_bytes[i], wallet2ext.random_bytes[i]);
+ assertEquals("Wallet extension byte different at byte " + i, wallet1.random_bytes[i], wallet2ext.random_bytes[i]);
}
}
@@ -277,7 +284,7 @@ public class WalletProtobufSerializerTest {
}
- private Wallet roundTripExtension(Wallet wallet) throws IOException {
+ private Wallet roundTripExtension(Wallet wallet) throws Exception {
ByteArrayOutputStream output = new ByteArrayOutputStream();
WalletProtobufSerializer serializer = new WalletProtobufSerializer();
@@ -320,7 +327,13 @@ public class WalletProtobufSerializerTest {
public Wallet newWallet(NetworkParameters params) {
return new WalletExtension(params);
}
-
+
+ @Override
+ public Wallet newWallet(NetworkParameters params, KeyCrypter keyCrypter) {
+ // Ignore encryption.
+ return new WalletExtension(params);
+ }
+
@Override
public void readExtension(Wallet wallet, Protos.Extension extProto) {
if (wallet instanceof WalletExtension) {
diff --git a/examples/src/main/java/com/google/bitcoin/examples/PeerMonitor.java b/examples/src/main/java/com/google/bitcoin/examples/PeerMonitor.java
index d9a5c0f2..6de99816 100644
--- a/examples/src/main/java/com/google/bitcoin/examples/PeerMonitor.java
+++ b/examples/src/main/java/com/google/bitcoin/examples/PeerMonitor.java
@@ -288,7 +288,7 @@ public class PeerMonitor {
if (column == PeerTableModel.CHAIN_HEIGHT) {
long height = (Long) contents;
if (height != peerGroup.getMostCommonChainHeight()) {
- str = height + " • ";
+ str = height + " \u2022 ";
}
}
}
diff --git a/examples/src/main/java/com/google/bitcoin/examples/PingService.java b/examples/src/main/java/com/google/bitcoin/examples/PingService.java
index 88cb5994..4d032b03 100644
--- a/examples/src/main/java/com/google/bitcoin/examples/PingService.java
+++ b/examples/src/main/java/com/google/bitcoin/examples/PingService.java
@@ -17,6 +17,7 @@
package com.google.bitcoin.examples;
import com.google.bitcoin.core.*;
+import com.google.bitcoin.crypto.KeyCrypterException;
import com.google.bitcoin.discovery.DnsDiscovery;
import com.google.bitcoin.discovery.IrcDiscovery;
import com.google.bitcoin.store.BlockStore;
@@ -188,6 +189,9 @@ public class PingService {
} catch (ScriptException e) {
// If we didn't understand the scriptSig, just crash.
throw new RuntimeException(e);
+ } catch (KeyCrypterException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
}
}
}
diff --git a/pom.xml b/pom.xml
index 96584587..eedd1068 100644
--- a/pom.xml
+++ b/pom.xml
@@ -189,6 +189,13 @@
protobuf-java
${protobuf.version}
+
+
+ com.lambdaworks
+ scrypt
+ 1.3.3
+
+
@@ -206,5 +213,4 @@
3.6.3.Final
gen
-
diff --git a/tools/src/main/java/com/google/bitcoin/tools/WalletTool.java b/tools/src/main/java/com/google/bitcoin/tools/WalletTool.java
index 988848c0..33bc6240 100644
--- a/tools/src/main/java/com/google/bitcoin/tools/WalletTool.java
+++ b/tools/src/main/java/com/google/bitcoin/tools/WalletTool.java
@@ -17,6 +17,7 @@
package com.google.bitcoin.tools;
import com.google.bitcoin.core.*;
+import com.google.bitcoin.crypto.KeyCrypterException;
import com.google.bitcoin.discovery.DnsDiscovery;
import com.google.bitcoin.discovery.IrcDiscovery;
import com.google.bitcoin.discovery.PeerDiscovery;
@@ -432,6 +433,8 @@ public class WalletTool {
return;
} catch (ScriptException e) {
throw new RuntimeException(e);
+ } catch (KeyCrypterException e) {
+ throw new RuntimeException(e);
}
t = req.tx; // Not strictly required today.
setup();
@@ -443,6 +446,8 @@ public class WalletTool {
System.out.println(t.getHashAsString());
} catch (BlockStoreException e) {
throw new RuntimeException(e);
+ } catch (KeyCrypterException e) {
+ throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
@@ -666,7 +671,11 @@ public class WalletTool {
System.err.println("That key already exists in this wallet.");
return;
}
- wallet.addKey(key);
+ try {
+ wallet.addKey(key);
+ } catch (KeyCrypterException kce) {
+ System.err.println("There was an encryption related error when adding the key. The error was '" + kce.getMessage() + "'.");
+ }
System.out.println("addr:" + key.toAddress(params) + " " + key);
}