com.google.bitcoin.core.Sha256Hash Maven / Gradle / Ivy
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.core;
import com.google.common.io.ByteStreams;
import org.spongycastle.util.encoders.Hex;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkArgument;
/**
* A Sha256Hash just wraps a byte[] so that equals and hashcode work correctly, allowing it to be used as keys in a
* map. It also checks that the length is correct and provides a bit more type safety.
*/
public class Sha256Hash implements Serializable, Comparable {
private byte[] bytes;
public static final Sha256Hash ZERO_HASH = new Sha256Hash(new byte[32]);
/**
* Creates a Sha256Hash by wrapping the given byte array. It must be 32 bytes long.
*/
public Sha256Hash(byte[] rawHashBytes) {
checkArgument(rawHashBytes.length == 32);
this.bytes = rawHashBytes;
}
/**
* Creates a Sha256Hash by decoding the given hex string. It must be 64 characters long.
*/
public Sha256Hash(String hexString) {
checkArgument(hexString.length() == 64);
this.bytes = Hex.decode(hexString);
}
/**
* Calculates the (one-time) hash of contents and returns it as a new wrapped hash.
*/
public static Sha256Hash create(byte[] contents) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return new Sha256Hash(digest.digest(contents));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/**
* Calculates the hash of the hash of the contents. This is a standard operation in Bitcoin.
*/
public static Sha256Hash createDouble(byte[] contents) {
return new Sha256Hash(Utils.doubleDigest(contents));
}
/**
* Returns a hash of the given files contents. Reads the file fully into memory before hashing so only use with
* small files.
* @throws IOException
*/
public static Sha256Hash hashFileContents(File f) throws IOException {
FileInputStream in = new FileInputStream(f);
try {
return create(ByteStreams.toByteArray(in));
} finally {
in.close();
}
}
/**
* Returns true if the hashes are equal.
*/
@Override
public boolean equals(Object other) {
if (!(other instanceof Sha256Hash)) return false;
return Arrays.equals(bytes, ((Sha256Hash) other).bytes);
}
/**
* 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.
*/
@Override
public int hashCode() {
// Use the last 4 bytes, not the first 4 which are often zeros in Bitcoin.
return (bytes[31] & 0xFF) | ((bytes[30] & 0xFF) << 8) | ((bytes[29] & 0xFF) << 16) | ((bytes[28] & 0xFF) << 24);
}
@Override
public String toString() {
return Utils.bytesToHexString(bytes);
}
/**
* Returns the bytes interpreted as a positive integer.
*/
public BigInteger toBigInteger() {
return new BigInteger(1, bytes);
}
public byte[] getBytes() {
return bytes;
}
public Sha256Hash duplicate() {
return new Sha256Hash(bytes);
}
@Override
public int compareTo(Object o) {
checkArgument(o instanceof Sha256Hash);
int thisCode = this.hashCode();
int oCode = ((Sha256Hash)o).hashCode();
return thisCode > oCode ? 1 : (thisCode == oCode ? 0 : -1);
}
}