com.swirlds.common.crypto.HashBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swirlds-common Show documentation
Show all versions of swirlds-common Show documentation
Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.
/*
* Copyright (C) 2016-2024 Hedera Hashgraph, LLC
*
* 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.swirlds.common.crypto;
import com.swirlds.logging.legacy.LogMarker;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Objects;
public class HashBuilder {
private MessageDigest digest;
private DigestType digestType;
public HashBuilder(final MessageDigest digest) {
if (digest == null) {
throw new IllegalArgumentException("digest");
}
this.digest = digest;
detectDigestType();
}
public HashBuilder(final DigestType digestType) {
if (digestType == null) {
throw new IllegalArgumentException("digestType");
}
this.digestType = digestType;
initializeDigest();
}
/**
* hash the given long
*
* @param n
* the long value to be hashed
* @return the HashBuilder object after digesting this long number
*/
public HashBuilder update(long n) {
for (int i = 0; i < Long.BYTES; i++) {
digest.update((byte) (n & 0xFF));
n >>= Byte.SIZE;
}
return this;
}
/**
* hash the given int
*
* @param n
* the int value to be hashed
* @return the HashBuilder object after digesting this int number
*/
public HashBuilder update(int n) {
for (int i = 0; i < Integer.BYTES; i++) {
digest.update((byte) (n & 0xFF));
n >>= Byte.SIZE;
}
return this;
}
/**
* hash the given array of bytes
*
* @param t
* the array of bytes
* @param offset
* the offset to start from in the array of bytes
* @param length
* the number of bytes to use, starting at {@code offset}
* @return the HashBuilder object after digesting this int number
*/
public HashBuilder update(byte[] t, int offset, int length) {
if (t == null) {
update(0);
} else {
update(t.length);
digest.update(t, offset, length);
}
return this;
}
/**
* hash the given Instant
*
* @param i
* the Instant object to be hashed
* @return the HashBuilder object after digesting this Instant object
*/
public HashBuilder update(Instant i) {
// the instant class consists of only 2 parts, the seconds and the nanoseconds
update(i.getEpochSecond());
update(i.getNano());
return this;
}
/**
* hash the given array of byte arrays
*
* @param t
* the array of byte arrays to be hashed
* @return the HashBuilder object after digesting this array
*/
public HashBuilder update(byte[][] t) {
if (t == null) {
update(0);
} else {
update(t.length);
for (byte[] a : t) {
if (a == null) {
update(0);
} else {
update(a.length);
digest.update(a);
}
}
}
return this;
}
/**
* hash the given array of bytes, including its length
*
* @param t
* the byte arrays to be hashed
* @return the HashBuilder object after digesting this array
*/
public HashBuilder update(byte[] t) {
if (t == null) {
update(0);
} else {
update(t.length);
digest.update(t);
}
return this;
}
/**
* Temporary method until we change how we hash all objects
*
* @param hash
* the Hash object to be hashed
* @return the HashBuilder object after digesting this Hash object
*/
public HashBuilder update(final Hash hash) {
if (hash == null) {
throw new IllegalArgumentException("hash");
}
hash.getBytes().writeTo(digest);
return this;
}
/**
* hash the given array of bytes, not including its length
*
* @param data
* the byte arrays to be hashed
* @return the HashBuilder object after digesting this array
*/
public HashBuilder updateRaw(final byte[] data) {
if (data == null || data.length == 0) {
throw new IllegalArgumentException("data");
}
digest.update(data);
return this;
}
/**
* resets the digest
*
* @return the HashBuilder object after the digest is reset
*/
public HashBuilder reset() {
digest.reset();
return this;
}
/**
* @return a mutable Hash
*/
public Hash build() {
return mutable();
}
/**
* @return a mutable Hash
*/
public Hash mutable() {
return new Hash(digest.digest(), digestType);
}
/**
* @return an immutable Hash
*/
public ImmutableHash immutable() {
return new ImmutableHash(digest.digest(), digestType);
}
/**
* initializes the digest object
*/
private void initializeDigest() {
try {
digest = MessageDigest.getInstance(digestType.algorithmName());
} catch (NoSuchAlgorithmException ex) {
throw new CryptographyException(ex, LogMarker.EXCEPTION);
}
}
/**
* checks whether the digestType is valid
*/
private void detectDigestType() {
for (DigestType t : DigestType.values()) {
if (Objects.equals(t.algorithmName(), digest.getAlgorithm())) {
digestType = t;
break;
}
}
if (digestType == null) {
throw new InvalidDigestTypeException(digest.getAlgorithm());
}
}
}