From 6aa4e51de6004f7171802bbce9c1660228d05aae Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 5 Mar 2015 13:59:15 -0800 Subject: [PATCH] Sha256Hash: some tweaks and renamings in the API (backwards compatible). --- .../main/java/org/bitcoinj/core/Block.java | 6 ++-- .../java/org/bitcoinj/core/Sha256Hash.java | 35 ++++++++++++------- .../org/bitcoinj/crypto/MnemonicCode.java | 4 +-- .../bitcoinj/net/discovery/HttpDiscovery.java | 2 +- .../PaymentChannelClientConnection.java | 2 +- .../java/org/bitcoinj/core/BlockTest.java | 4 +-- .../java/org/bitcoinj/core/ECKeyTest.java | 6 ++-- .../bitcoinj/core/FullBlockTestGenerator.java | 2 +- .../test/java/org/bitcoinj/core/PeerTest.java | 8 ++--- .../crypto/ChildKeyDerivationTest.java | 2 +- .../channels/ChannelConnectionTest.java | 4 +-- .../channels/PaymentChannelClientTest.java | 2 +- .../channels/PaymentChannelStateTest.java | 2 +- .../wallet/DeterministicKeyChainTest.java | 6 +--- .../bitcoinj/wallet/KeyChainGroupTest.java | 3 +- 15 files changed, 47 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/org/bitcoinj/core/Block.java b/core/src/main/java/org/bitcoinj/core/Block.java index 31f17b96..ea1288ad 100644 --- a/core/src/main/java/org/bitcoinj/core/Block.java +++ b/core/src/main/java/org/bitcoinj/core/Block.java @@ -562,13 +562,13 @@ public class Block extends Message { maybeParseHeader(); Block block = new Block(params); block.nonce = nonce; - block.prevBlockHash = prevBlockHash.duplicate(); - block.merkleRoot = getMerkleRoot().duplicate(); + block.prevBlockHash = prevBlockHash; + block.merkleRoot = getMerkleRoot(); block.version = version; block.time = time; block.difficultyTarget = difficultyTarget; block.transactions = null; - block.hash = getHash().duplicate(); + block.hash = getHash(); return block; } diff --git a/core/src/main/java/org/bitcoinj/core/Sha256Hash.java b/core/src/main/java/org/bitcoinj/core/Sha256Hash.java index 9d37628f..5ad6ee69 100644 --- a/core/src/main/java/org/bitcoinj/core/Sha256Hash.java +++ b/core/src/main/java/org/bitcoinj/core/Sha256Hash.java @@ -54,10 +54,16 @@ public class Sha256Hash implements Serializable, Comparable { this.bytes = Utils.HEX.decode(hexString); } - /** - * Calculates the (one-time) hash of contents and returns it as a new wrapped hash. - */ + /** Use Sha256Hash.hash(byte[]) instead: this old name is ambiguous */ + @Deprecated public static Sha256Hash create(byte[] contents) { + return hash(contents); + } + + /** + * Calculates the (one-time) hash of contents and returns it. + */ + public static Sha256Hash hash(byte[] contents) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); return new Sha256Hash(digest.digest(contents)); @@ -66,10 +72,16 @@ public class Sha256Hash implements Serializable, Comparable { } } + /** Use hashTwice(byte[]) instead: this old name is ambiguous. */ + @Deprecated + public static Sha256Hash createDouble(byte[] contents) { + return hashTwice(contents); + } + /** * Calculates the hash of the hash of the contents. This is a standard operation in Bitcoin. */ - public static Sha256Hash createDouble(byte[] contents) { + public static Sha256Hash hashTwice(byte[] contents) { return new Sha256Hash(Utils.doubleDigest(contents)); } @@ -81,7 +93,7 @@ public class Sha256Hash implements Serializable, Comparable { public static Sha256Hash hashFileContents(File f) throws IOException { FileInputStream in = new FileInputStream(f); try { - return create(ByteStreams.toByteArray(in)); + return hash(ByteStreams.toByteArray(in)); } finally { in.close(); } @@ -96,9 +108,9 @@ public class Sha256Hash implements Serializable, Comparable { } /** - * Hash code of the byte array as calculated by {@link Arrays#hashCode()}. Note the difference between a SHA256 - * secure bytes and the type of quick/dirty bytes used by the Java hashCode method which is designed for use in - * bytes tables. + * Returns the last four bytes of the wrapped hash. This should be unique enough to be a suitable hash code even for + * blocks, where the goal is to try and get the first bytes to be zeros (i.e. the value as a big integer lower + * than the target value). */ @Override public int hashCode() { @@ -118,14 +130,13 @@ public class Sha256Hash implements Serializable, Comparable { return new BigInteger(1, bytes); } + /** + * Returns the internal byte array, without defensively copying. Therefore do NOT modify the returned array. + */ public byte[] getBytes() { return bytes; } - public Sha256Hash duplicate() { - return new Sha256Hash(bytes); - } - @Override public int compareTo(Sha256Hash o) { int thisCode = this.hashCode(); diff --git a/core/src/main/java/org/bitcoinj/crypto/MnemonicCode.java b/core/src/main/java/org/bitcoinj/crypto/MnemonicCode.java index 2b1272a4..9e9cd829 100644 --- a/core/src/main/java/org/bitcoinj/crypto/MnemonicCode.java +++ b/core/src/main/java/org/bitcoinj/crypto/MnemonicCode.java @@ -180,7 +180,7 @@ public class MnemonicCode { entropy[ii] |= 1 << (7 - jj); // Take the digest of the entropy. - byte[] hash = Sha256Hash.create(entropy).getBytes(); + byte[] hash = Sha256Hash.hash(entropy).getBytes(); boolean[] hashBits = bytesToBits(hash); // Check all the checksum bits. @@ -204,7 +204,7 @@ public class MnemonicCode { // We take initial entropy of ENT bits and compute its // checksum by taking first ENT / 32 bits of its SHA256 hash. - byte[] hash = Sha256Hash.create(entropy).getBytes(); + byte[] hash = Sha256Hash.hash(entropy).getBytes(); boolean[] hashBits = bytesToBits(hash); boolean[] entropyBits = bytesToBits(entropy); diff --git a/core/src/main/java/org/bitcoinj/net/discovery/HttpDiscovery.java b/core/src/main/java/org/bitcoinj/net/discovery/HttpDiscovery.java index 318573fc..06c333b4 100644 --- a/core/src/main/java/org/bitcoinj/net/discovery/HttpDiscovery.java +++ b/core/src/main/java/org/bitcoinj/net/discovery/HttpDiscovery.java @@ -77,7 +77,7 @@ public class HttpDiscovery implements PeerDiscovery { if (pubkey != null) { if (!Arrays.equals(proto.getPubkey().toByteArray(), pubkey.getPubKey())) throw new PeerDiscoveryException("Public key mismatch"); - Sha256Hash hash = Sha256Hash.create(proto.getPeerSeeds().toByteArray()); + Sha256Hash hash = Sha256Hash.hash(proto.getPeerSeeds().toByteArray()); pubkey.verifyOrThrow(hash.getBytes(), proto.getSignature().toByteArray()); } PeerSeedProtos.PeerSeeds seeds = PeerSeedProtos.PeerSeeds.parseFrom(proto.getPeerSeeds()); diff --git a/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelClientConnection.java b/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelClientConnection.java index b39a2592..2216dd0d 100644 --- a/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelClientConnection.java +++ b/core/src/main/java/org/bitcoinj/protocols/channels/PaymentChannelClientConnection.java @@ -101,7 +101,7 @@ public class PaymentChannelClientConnection { throws IOException, ValueOutOfRangeException { // Glue the object which vends/ingests protobuf messages in order to manage state to the network object which // reads/writes them to the wire in length prefixed form. - channelClient = new PaymentChannelClient(wallet, myKey, maxValue, Sha256Hash.create(serverId.getBytes()), timeWindow, + channelClient = new PaymentChannelClient(wallet, myKey, maxValue, Sha256Hash.hash(serverId.getBytes()), timeWindow, userKeySetup, new PaymentChannelClient.ClientConnection() { @Override public void sendToServer(Protos.TwoWayChannelMessage msg) { diff --git a/core/src/test/java/org/bitcoinj/core/BlockTest.java b/core/src/test/java/org/bitcoinj/core/BlockTest.java index 7a93c666..49a143ae 100644 --- a/core/src/test/java/org/bitcoinj/core/BlockTest.java +++ b/core/src/test/java/org/bitcoinj/core/BlockTest.java @@ -167,7 +167,7 @@ public class BlockTest { Arrays.fill(outputScript, (byte) ScriptOpCodes.OP_FALSE); tx.addOutput(new TransactionOutput(params, null, Coin.SATOSHI, outputScript)); tx.addInput(new TransactionInput(params, null, new byte[] {(byte) ScriptOpCodes.OP_FALSE}, - new TransactionOutPoint(params, 0, Sha256Hash.create(new byte[] {1})))); + new TransactionOutPoint(params, 0, Sha256Hash.hash(new byte[]{1})))); int origTxLength = 8 + 2 + 8 + 1 + 10 + 40 + 1 + 1; assertEquals(tx.bitcoinSerialize().length, tx.length); assertEquals(origTxLength, tx.length); @@ -182,7 +182,7 @@ public class BlockTest { assertEquals(block.length, origBlockLen + tx.length); assertEquals(tx.length, origTxLength - 1); block.getTransactions().get(1).addInput(new TransactionInput(params, null, new byte[] {(byte) ScriptOpCodes.OP_FALSE}, - new TransactionOutPoint(params, 0, Sha256Hash.create(new byte[] {1})))); + new TransactionOutPoint(params, 0, Sha256Hash.hash(new byte[]{1})))); assertEquals(block.length, origBlockLen + tx.length); assertEquals(tx.length, origTxLength + 41); // - 1 + 40 + 1 + 1 } diff --git a/core/src/test/java/org/bitcoinj/core/ECKeyTest.java b/core/src/test/java/org/bitcoinj/core/ECKeyTest.java index 6febe6bc..c0e8a9de 100644 --- a/core/src/test/java/org/bitcoinj/core/ECKeyTest.java +++ b/core/src/test/java/org/bitcoinj/core/ECKeyTest.java @@ -87,7 +87,7 @@ public class ECKeyTest { List> sigFutures = Lists.newArrayList(); final ECKey key = new ECKey(); for (byte i = 0; i < ITERATIONS; i++) { - final Sha256Hash hash = Sha256Hash.create(new byte[]{i}); + final Sha256Hash hash = Sha256Hash.hash(new byte[]{i}); sigFutures.add(executor.submit(new Callable() { @Override public ECKey.ECDSASignature call() throws Exception { @@ -247,7 +247,7 @@ public class ECKeyTest { public void keyRecovery() throws Exception { ECKey key = new ECKey(); String message = "Hello World!"; - Sha256Hash hash = Sha256Hash.create(message.getBytes()); + Sha256Hash hash = Sha256Hash.hash(message.getBytes()); ECKey.ECDSASignature sig = key.sign(hash); key = ECKey.fromPublicOnly(key.getPubKeyPoint()); boolean found = false; @@ -346,7 +346,7 @@ public class ECKeyTest { ECKey encryptedKey = unencryptedKey.encrypt(keyCrypter, aesKey); String message = "Goodbye Jupiter!"; - Sha256Hash hash = Sha256Hash.create(message.getBytes()); + Sha256Hash hash = Sha256Hash.hash(message.getBytes()); ECKey.ECDSASignature sig = encryptedKey.sign(hash, aesKey); unencryptedKey = ECKey.fromPublicOnly(unencryptedKey.getPubKeyPoint()); boolean found = false; diff --git a/core/src/test/java/org/bitcoinj/core/FullBlockTestGenerator.java b/core/src/test/java/org/bitcoinj/core/FullBlockTestGenerator.java index 73c8d68d..7b104dc2 100644 --- a/core/src/test/java/org/bitcoinj/core/FullBlockTestGenerator.java +++ b/core/src/test/java/org/bitcoinj/core/FullBlockTestGenerator.java @@ -981,7 +981,7 @@ public class FullBlockTestGenerator { NewBlock b49 = createNextBlock(b44, chainHeadHeight + 16, out15, null); byte[] b49MerkleHash = Sha256Hash.ZERO_HASH.getBytes().clone(); b49MerkleHash[1] = (byte) 0xDE; - b49.block.setMerkleRoot(Sha256Hash.create(b49MerkleHash)); + b49.block.setMerkleRoot(Sha256Hash.hash(b49MerkleHash)); b49.solve(); blocks.add(new BlockAndValidity(b49, false, true, b44.getHash(), chainHeadHeight + 15, "b49")); diff --git a/core/src/test/java/org/bitcoinj/core/PeerTest.java b/core/src/test/java/org/bitcoinj/core/PeerTest.java index 45c57b23..aa707bd1 100644 --- a/core/src/test/java/org/bitcoinj/core/PeerTest.java +++ b/core/src/test/java/org/bitcoinj/core/PeerTest.java @@ -708,7 +708,7 @@ public class PeerTest extends TestWithNetworkConnections { Transaction t2 = new Transaction(unitTestParams); t2.setLockTime(999999); // Add a fake input to t3 that goes nowhere. - Sha256Hash t3 = Sha256Hash.create("abc".getBytes(Charset.forName("UTF-8"))); + Sha256Hash t3 = Sha256Hash.hash("abc".getBytes(Charset.forName("UTF-8"))); t2.addInput(new TransactionInput(unitTestParams, t2, new byte[]{}, new TransactionOutPoint(unitTestParams, 0, t3))); t2.getInput(0).setSequenceNumber(0xDEADBEEF); t2.addOutput(COIN, new ECKey()); @@ -842,9 +842,9 @@ public class PeerTest extends TestWithNetworkConnections { @Override public void bitcoinSerializeToStream(OutputStream stream) throws IOException { // Add some hashes. - addItem(new InventoryItem(InventoryItem.Type.Transaction, Sha256Hash.create(new byte[] { 1 }))); - addItem(new InventoryItem(InventoryItem.Type.Transaction, Sha256Hash.create(new byte[] { 2 }))); - addItem(new InventoryItem(InventoryItem.Type.Transaction, Sha256Hash.create(new byte[] { 3 }))); + addItem(new InventoryItem(InventoryItem.Type.Transaction, Sha256Hash.hash(new byte[]{1}))); + addItem(new InventoryItem(InventoryItem.Type.Transaction, Sha256Hash.hash(new byte[]{2}))); + addItem(new InventoryItem(InventoryItem.Type.Transaction, Sha256Hash.hash(new byte[]{3}))); // Write out a copy that's truncated in the middle. ByteArrayOutputStream bos = new ByteArrayOutputStream(); diff --git a/core/src/test/java/org/bitcoinj/crypto/ChildKeyDerivationTest.java b/core/src/test/java/org/bitcoinj/crypto/ChildKeyDerivationTest.java index 5606eccd..1a684dbb 100644 --- a/core/src/test/java/org/bitcoinj/crypto/ChildKeyDerivationTest.java +++ b/core/src/test/java/org/bitcoinj/crypto/ChildKeyDerivationTest.java @@ -157,7 +157,7 @@ public class ChildKeyDerivationTest { assertFalse(decryptedKey2.isEncrypted()); assertEquals(key2, decryptedKey2); - Sha256Hash hash = Sha256Hash.create("the mainstream media won't cover it. why is that?".getBytes()); + Sha256Hash hash = Sha256Hash.hash("the mainstream media won't cover it. why is that?".getBytes()); try { derivedKey2.sign(hash); fail(); diff --git a/core/src/test/java/org/bitcoinj/protocols/channels/ChannelConnectionTest.java b/core/src/test/java/org/bitcoinj/protocols/channels/ChannelConnectionTest.java index 5f2e2435..a391a658 100644 --- a/core/src/test/java/org/bitcoinj/protocols/channels/ChannelConnectionTest.java +++ b/core/src/test/java/org/bitcoinj/protocols/channels/ChannelConnectionTest.java @@ -290,7 +290,7 @@ public class ChannelConnectionTest extends TestWithWallet { // Tests various aspects of channel resuming. Utils.setMockClock(); - final Sha256Hash someServerId = Sha256Hash.create(new byte[]{}); + final Sha256Hash someServerId = Sha256Hash.hash(new byte[]{}); // Open up a normal channel. ChannelTestUtils.RecordingPair pair = ChannelTestUtils.makeRecorders(serverWallet, mockBroadcaster); @@ -340,7 +340,7 @@ public class ChannelConnectionTest extends TestWithWallet { pair.server.receiveMessage(Protos.TwoWayChannelMessage.newBuilder() .setType(MessageType.CLIENT_VERSION) .setClientVersion(Protos.ClientVersion.newBuilder() - .setPreviousChannelContractHash(ByteString.copyFrom(Sha256Hash.create(new byte[]{0x03}).getBytes())) + .setPreviousChannelContractHash(ByteString.copyFrom(Sha256Hash.hash(new byte[]{0x03}).getBytes())) .setMajor(CLIENT_MAJOR_VERSION).setMinor(42)) .build()); pair.serverRecorder.checkNextMsg(MessageType.SERVER_VERSION); diff --git a/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelClientTest.java b/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelClientTest.java index ba48acf0..7ed2e3f6 100644 --- a/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelClientTest.java +++ b/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelClientTest.java @@ -33,7 +33,7 @@ public class PaymentChannelClientTest { wallet = createMock(Wallet.class); ecKey = createMock(ECKey.class); maxValue = Coin.COIN; - serverHash = Sha256Hash.create("serverId".getBytes()); + serverHash = Sha256Hash.hash("serverId".getBytes()); connection = createMock(IPaymentChannelClient.ClientConnection.class); clientVersionCapture = new Capture(); } diff --git a/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelStateTest.java b/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelStateTest.java index 78d06a60..df024011 100644 --- a/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelStateTest.java +++ b/core/src/test/java/org/bitcoinj/protocols/channels/PaymentChannelStateTest.java @@ -292,7 +292,7 @@ public class PaymentChannelStateTest extends TestWithWallet { Utils.rollMockClock(60 * 60 * 2 + 60 * 5); // Now store the client state in a stored state object which handles the rebroadcasting - clientState.doStoreChannelInWallet(Sha256Hash.create(new byte[]{})); + clientState.doStoreChannelInWallet(Sha256Hash.hash(new byte[]{})); TxFuturePair clientBroadcastedMultiSig = broadcasts.take(); TxFuturePair broadcastRefund = broadcasts.take(); assertEquals(clientBroadcastedMultiSig.tx.getHash(), multisigContract.getHash()); diff --git a/core/src/test/java/org/bitcoinj/wallet/DeterministicKeyChainTest.java b/core/src/test/java/org/bitcoinj/wallet/DeterministicKeyChainTest.java index 9d2bd6cc..a33df287 100644 --- a/core/src/test/java/org/bitcoinj/wallet/DeterministicKeyChainTest.java +++ b/core/src/test/java/org/bitcoinj/wallet/DeterministicKeyChainTest.java @@ -25,10 +25,6 @@ import org.bitcoinj.store.UnreadableWalletException; import org.bitcoinj.utils.BriefLogFormatter; import org.bitcoinj.utils.Threading; import com.google.common.collect.Lists; -import org.bitcoinj.wallet.AbstractKeyChainEventListener; -import org.bitcoinj.wallet.DeterministicKeyChain; -import org.bitcoinj.wallet.KeyChain; -import org.bitcoinj.wallet.Protos; import org.junit.Before; import org.junit.Test; import org.spongycastle.crypto.params.KeyParameter; @@ -42,7 +38,7 @@ import static org.junit.Assert.*; public class DeterministicKeyChainTest { private DeterministicKeyChain chain; - private final byte[] ENTROPY = Sha256Hash.create("don't use a string seed like this in real life".getBytes()).getBytes(); + private final byte[] ENTROPY = Sha256Hash.hash("don't use a string seed like this in real life".getBytes()).getBytes(); @Before public void setup() { diff --git a/core/src/test/java/org/bitcoinj/wallet/KeyChainGroupTest.java b/core/src/test/java/org/bitcoinj/wallet/KeyChainGroupTest.java index d7b02f47..eaf84a48 100644 --- a/core/src/test/java/org/bitcoinj/wallet/KeyChainGroupTest.java +++ b/core/src/test/java/org/bitcoinj/wallet/KeyChainGroupTest.java @@ -22,7 +22,6 @@ import org.bitcoinj.params.MainNetParams; import org.bitcoinj.utils.BriefLogFormatter; import org.bitcoinj.utils.Threading; import com.google.common.collect.ImmutableList; -import org.bitcoinj.wallet.*; import org.junit.Before; import org.junit.Test; import org.spongycastle.crypto.params.KeyParameter; @@ -65,7 +64,7 @@ public class KeyChainGroupTest { } private MarriedKeyChain createMarriedKeyChain() { - byte[] entropy = Sha256Hash.create("don't use a seed like this in real life".getBytes()).getBytes(); + byte[] entropy = Sha256Hash.hash("don't use a seed like this in real life".getBytes()).getBytes(); DeterministicSeed seed = new DeterministicSeed(entropy, "", MnemonicCode.BIP39_STANDARDISATION_TIME_SECS); MarriedKeyChain chain = MarriedKeyChain.builder() .seed(seed)