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

org.protelis.vm.impl.HashingCodePathFactory Maven / Gradle / Ivy

There is a newer version: 17.6.0
Show newest version
/*
 * Copyright (C) 2021, Danilo Pianini and contributors listed in the project's build.gradle.kts or pom.xml file.
 *
 * This file is part of Protelis, and is distributed under the terms of the GNU General Public License,
 * with a linking exception, as described in the file LICENSE.txt in this project's top directory.
 */

package org.protelis.vm.impl;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Base64;
import java.util.function.Supplier;

import org.protelis.vm.CodePath;
import org.protelis.vm.CodePathFactory;

import com.google.common.hash.HashFunction;
import com.google.common.hash.Hasher;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import gnu.trove.list.TIntList;
import gnu.trove.stack.TIntStack;

/**
 * A hash-based {@link CodePath} factory. It allows for predictable packet
 * sizes, as codepath length is no affected by the evaluation tree depth at
 * which the field was built. It is arguably more secure than the default option
 * (if a cryptographic hashing function is used) as receivers cannot deduce the
 * code that generated some values. The provided factory is configurable by
 * using an {@link HashFunction} from Guava. Being hash based, it has a non-zero
 * probability of collision. Using decent hash functions (e.g. SHA) should
 * however make the event very unlikely. In any case, there is a trade-off
 * between collision probability and packet size.
 * 
 * Implementations of {@link AbstractExecutionContext} can use it by passing the
 * factory instance in the super constructor call, e.g.:
 * 
 * 
 * super(execenv, netmgr, new HashingCodePathFactory(Hashing.sha256()));
 * 
* */ @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "False positive, checked by a test.") public class HashingCodePathFactory implements CodePathFactory { private static final long serialVersionUID = 1L; private final HasherSupplier algorithm; /** * @param hashFunction the hashing algorithm to use */ public HashingCodePathFactory(final HasherSupplier hashFunction) { algorithm = hashFunction; } /** * @param hashFunction the hashing algorithm to use */ public HashingCodePathFactory(final HashFunction hashFunction) { this(hashFunction::newHasher); } @Override public final CodePath createCodePath(final TIntList callStackIdentifiers, final TIntStack callStackSizes) { final Hasher hasher = algorithm.get(); callStackIdentifiers.forEach(it -> { hasher.putInt(it); return true; }); return new HashingCodePath(hasher.hash().asBytes(), false); } /** * Serializable supplier, because Java 8 lambdas are not. */ @FunctionalInterface public interface HasherSupplier extends Supplier, Serializable { } /** * Hash-based {@link CodePath}. */ public static final class HashingCodePath implements CodePath { private static final long serialVersionUID = 1L; private final byte[] hash; /** * Builds a new {@link HashingCodePath} based on the provided hash. * * @param hash a byte array representing the hash it must be at least four bytes * (though longer hashes are warmly recommended to avoid collisions) */ public HashingCodePath(final byte[] hash) { this(hash, true); } private HashingCodePath(final byte[] hash, final boolean copy) { if (hash.length < 4) { throw new IllegalArgumentException("Hashes shorter than four bytes are unacceptable: " + Arrays.toString(hash)); } this.hash = copy ? Arrays.copyOf(hash, hash.length) : hash; } @Override public boolean equals(final Object obj) { return obj instanceof HashingCodePath && Arrays.equals(hash, ((HashingCodePath) obj).hash); } /** * @return a byte[] representation of the hash. The returned array does not map * on the internal status of {@link HashingCodePath} and can get * modified. */ public byte[] getHash() { return Arrays.copyOf(hash, hash.length); } @Override public int hashCode() { // CHECKSTYLE: MagicNumber OFF return (hash[0] & 0xFF) | ((hash[1] & 0xFF) << 8) | ((hash[2] & 0xFF) << 16) | ((hash[3] & 0xFF) << 24); // CHECKSTYLE: MagicNumber ON } @Override public String toString() { return Base64.getEncoder().encodeToString(hash); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy