All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bitcoinj.base.Sha256Hash Maven / Gradle / Ivy

There is a newer version: 0.17-beta1
Show newest version
/*
 * 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.base;

import org.bitcoinj.base.internal.ByteUtils;

import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import static org.bitcoinj.base.internal.Preconditions.checkArgument;

/**
 * A {@code Sha256Hash} wraps a {@code byte[]} so that {@link #equals} and {@link #hashCode} work correctly, allowing it to be used as a key in a
 * map. It also checks that the {@code length} is correct (equal to {@link #LENGTH}) and provides a bit more type safety.
 * 

* Given that {@code Sha256Hash} instances can be created using {@link #wrapReversed(byte[])} or {@link #twiceOf(byte[])} or by wrapping raw bytes, there is no guarantee that if two {@code Sha256Hash} instances are found equal (via {@link #equals(Object)}) that their preimages would be the same (even in the absence of a hash collision.) */ public class Sha256Hash implements Comparable { public static final int LENGTH = 32; // bytes public static final Sha256Hash ZERO_HASH = wrap(new byte[LENGTH]); private final byte[] bytes; private Sha256Hash(byte[] rawHashBytes) { checkArgument(rawHashBytes.length == LENGTH, () -> "length must be " + LENGTH + ": " + rawHashBytes.length); this.bytes = rawHashBytes; } /** * 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 */ 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(ByteUtils.parseHex(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 */ public static Sha256Hash wrapReversed(byte[] rawHashBytes) { return wrap(ByteUtils.reverseBytes(rawHashBytes)); } /** * Create a new instance by reading from the given buffer. * * @param buf buffer to read from * @return a new instance * @throws BufferUnderflowException if the read hash extends beyond the remaining bytes of the buffer */ public static Sha256Hash read(ByteBuffer buf) throws BufferUnderflowException { byte[] b = new byte[32]; buf.get(b); // we have to flip it around, as on the wire it's in little endian return Sha256Hash.wrapReversed(b); } /** * 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)); } /** * 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 hash of the calculated hash of the given bytes. * * @param content1 first bytes on which the hash value is calculated * @param content2 second bytes on which the hash value is calculated * @return a new instance containing the calculated (two-time) hash */ public static Sha256Hash twiceOf(byte[] content1, byte[] content2) { return wrap(hashTwice(content1, content2)); } /** * 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 { return of(Files.readAllBytes(file.toPath())); } /** * 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 hash of hash on the given chunks of bytes. This is equivalent to concatenating the two * chunks and then passing the result to {@link #hashTwice(byte[])}. */ public static byte[] hashTwice(byte[] input1, byte[] input2) { MessageDigest digest = newDigest(); digest.update(input1); digest.update(input2); return digest.digest(digest.digest()); } /** * 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 ByteBuffer.wrap(bytes).getInt(LENGTH - Integer.BYTES); } @Override public String toString() { return ByteUtils.formatHex(bytes); } /** * Returns the bytes interpreted as a positive integer. */ public BigInteger toBigInteger() { return ByteUtils.bytesToBigInteger(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 ByteUtils.reverseBytes(bytes); } /** * Write hash into the given buffer. * * @param buf buffer to write into * @return the buffer * @throws BufferOverflowException if the hash doesn't fit the remaining buffer */ public ByteBuffer write(ByteBuffer buf) throws BufferOverflowException { // we have to flip it around, as on the wire it's in little endian buf.put(getReversedBytes()); return buf; } @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