org.bitcoinj.core.Sha256Hash Maven / Gradle / Ivy
/*
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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 org.bitcoinj.core;
import com.google.common.io.ByteStreams;
import com.google.common.primitives.*;
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 {
public static final int LENGTH = 32; // bytes
public static final Sha256Hash ZERO_HASH = wrap(new byte[LENGTH]);
private final byte[] bytes;
/**
* Use {@link #wrap(byte[])} instead.
*/
@Deprecated
public Sha256Hash(byte[] rawHashBytes) {
checkArgument(rawHashBytes.length == LENGTH);
this.bytes = rawHashBytes;
}
/**
* Use {@link #wrap(String)} instead.
*/
@Deprecated
public Sha256Hash(String hexString) {
checkArgument(hexString.length() == LENGTH * 2);
this.bytes = Utils.HEX.decode(hexString);
}
/**
* Creates a new instance that wraps the given hash value.
*
* @param rawHashBytes the raw hash bytes to wrap
* @return a new instance
* @throws IllegalArgumentException if the given array length is not exactly 32
*/
@SuppressWarnings("deprecation") // the constructor will be made private in the future
public static Sha256Hash wrap(byte[] rawHashBytes) {
return new Sha256Hash(rawHashBytes);
}
/**
* Creates a new instance that wraps the given hash value (represented as a hex string).
*
* @param hexString a hash value represented as a hex string
* @return a new instance
* @throws IllegalArgumentException if the given string is not a valid
* hex string, or if it does not represent exactly 32 bytes
*/
public static Sha256Hash wrap(String hexString) {
return wrap(Utils.HEX.decode(hexString));
}
/**
* Creates a new instance that wraps the given hash value, but with byte order reversed.
*
* @param rawHashBytes the raw hash bytes to wrap
* @return a new instance
* @throws IllegalArgumentException if the given array length is not exactly 32
*/
@SuppressWarnings("deprecation") // the constructor will be made private in the future
public static Sha256Hash wrapReversed(byte[] rawHashBytes) {
return wrap(Utils.reverseBytes(rawHashBytes));
}
/** Use {@link #of(byte[])} instead: this old name is ambiguous. */
@Deprecated
public static Sha256Hash create(byte[] contents) {
return of(contents);
}
/**
* Creates a new instance containing the calculated (one-time) hash of the given bytes.
*
* @param contents the bytes on which the hash value is calculated
* @return a new instance containing the calculated (one-time) hash
*/
public static Sha256Hash of(byte[] contents) {
return wrap(hash(contents));
}
/** Use {@link #twiceOf(byte[])} instead: this old name is ambiguous. */
@Deprecated
public static Sha256Hash createDouble(byte[] contents) {
return twiceOf(contents);
}
/**
* Creates a new instance containing the hash of the calculated hash of the given bytes.
*
* @param contents the bytes on which the hash value is calculated
* @return a new instance containing the calculated (two-time) hash
*/
public static Sha256Hash twiceOf(byte[] contents) {
return wrap(hashTwice(contents));
}
/**
* Creates a new instance containing the calculated (one-time) hash of the given file's contents.
*
* The file contents are read fully into memory, so this method should only be used with small files.
*
* @param file the file on which the hash value is calculated
* @return a new instance containing the calculated (one-time) hash
* @throws IOException if an error occurs while reading the file
*/
public static Sha256Hash of(File file) throws IOException {
FileInputStream in = new FileInputStream(file);
try {
return of(ByteStreams.toByteArray(in));
} finally {
in.close();
}
}
/**
* Returns a new SHA-256 MessageDigest instance.
*
* This is a convenience method which wraps the checked
* exception that can never occur with a RuntimeException.
*
* @return a new SHA-256 MessageDigest instance
*/
public static MessageDigest newDigest() {
try {
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Can't happen.
}
}
/**
* Calculates the SHA-256 hash of the given bytes.
*
* @param input the bytes to hash
* @return the hash (in big-endian order)
*/
public static byte[] hash(byte[] input) {
return hash(input, 0, input.length);
}
/**
* Calculates the SHA-256 hash of the given byte range.
*
* @param input the array containing the bytes to hash
* @param offset the offset within the array of the bytes to hash
* @param length the number of bytes to hash
* @return the hash (in big-endian order)
*/
public static byte[] hash(byte[] input, int offset, int length) {
MessageDigest digest = newDigest();
digest.update(input, offset, length);
return digest.digest();
}
/**
* Calculates the SHA-256 hash of the given bytes,
* and then hashes the resulting hash again.
*
* @param input the bytes to hash
* @return the double-hash (in big-endian order)
*/
public static byte[] hashTwice(byte[] input) {
return hashTwice(input, 0, input.length);
}
/**
* Calculates the SHA-256 hash of the given byte range,
* and then hashes the resulting hash again.
*
* @param input the array containing the bytes to hash
* @param offset the offset within the array of the bytes to hash
* @param length the number of bytes to hash
* @return the double-hash (in big-endian order)
*/
public static byte[] hashTwice(byte[] input, int offset, int length) {
MessageDigest digest = newDigest();
digest.update(input, offset, length);
return digest.digest(digest.digest());
}
/**
* Calculates the hash of hash on the given byte ranges. This is equivalent to
* concatenating the two ranges and then passing the result to {@link #hashTwice(byte[])}.
*/
public static byte[] hashTwice(byte[] input1, int offset1, int length1,
byte[] input2, int offset2, int length2) {
MessageDigest digest = newDigest();
digest.update(input1, offset1, length1);
digest.update(input2, offset2, length2);
return digest.digest(digest.digest());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return Arrays.equals(bytes, ((Sha256Hash)o).bytes);
}
/**
* 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() {
// Use the last 4 bytes, not the first 4 which are often zeros in Bitcoin.
return Ints.fromBytes(bytes[LENGTH - 4], bytes[LENGTH - 3], bytes[LENGTH - 2], bytes[LENGTH - 1]);
}
@Override
public String toString() {
return Utils.HEX.encode(bytes);
}
/**
* Returns the bytes interpreted as a positive integer.
*/
public BigInteger toBigInteger() {
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;
}
/**
* Returns a reversed copy of the internal byte array.
*/
public byte[] getReversedBytes() {
return Utils.reverseBytes(bytes);
}
@Override
public int compareTo(final Sha256Hash other) {
for (int i = LENGTH - 1; i >= 0; i--) {
final int thisByte = this.bytes[i] & 0xff;
final int otherByte = other.bytes[i] & 0xff;
if (thisByte > otherByte)
return 1;
if (thisByte < otherByte)
return -1;
}
return 0;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy