ch.openchvote.algorithms.Algorithm Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of algorithms Show documentation
Show all versions of algorithms Show documentation
This module contains implementations of all pseudocode algorithms contained in the CHVote protocol
specification.
The newest version!
/*
* Copyright (C) 2024 Berner Fachhochschule https://e-voting.bfh.ch
*
* - This program is free software: you can redistribute it and/or modify -
* - it under the terms of the GNU Affero General Public License as published by -
* - the Free Software Foundation, either version 3 of the License, or -
* - (at your option) any later version. -
* - -
* - This program is distributed in the hope that it will be useful, -
* - but WITHOUT ANY WARRANTY; without even the implied warranty of -
* - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -
* - GNU General Public License for more details. -
* - -
* - You should have received a copy of the GNU Affero General Public License -
* - along with this program. If not, see . -
*/
package ch.openchvote.algorithms;
import ch.openchvote.utilities.serializer.TypeReference;
import java.lang.reflect.Method;
import java.util.Arrays;
import static ch.openchvote.algorithms.Algorithm.Exception.Type.SERVICE_LOADING_PROBLEM;
import static ch.openchvote.algorithms.Algorithm.Exception.Type.UNDEFINED_TYPE_REFERENCE;
/**
* This is an abstract base class for algorithms to be called via an {@link AlgorithmService}. Implementing algorithm
* classes need to specify the type of the return value. Other than providing a static helper methods for obtaining the
* "run"-method implementing the algorithm and the corresponding return type, it does not offer any functionality.
*
* @param The type of the algorithm's return value
*/
@SuppressWarnings("unused")
public abstract class Algorithm {
// expected name of a static TypeReference field in the algorithm class
static private final String RETURN_TYPE_FIELD_NAME = "RETURN_TYPE";
// expected name of a method implementing the algorithm
static private final String ALGORITHM_METHOD_NAME = "run";
/**
* Returns the algorithm's "run"-method, which is expected to exist in the given algorithm class as a static method
* with the name as specified by {@link Algorithm#ALGORITHM_METHOD_NAME}.
*
* @param algorithmClass The given algorithm class
* @return The algorithm's "run"-method
* @throws Exception if no "run"-method is available in the given algorithm class
*/
static public Method getRunMethod(Class extends Algorithm>> algorithmClass) throws Exception {
return Arrays.stream(algorithmClass.getMethods())
.filter(method -> method.getName().equals(ALGORITHM_METHOD_NAME))
.findFirst()
.orElseThrow(() -> new Exception(SERVICE_LOADING_PROBLEM, algorithmClass));
}
/**
* Returns the type reference of the algorithm's return value. It is assumed that the type reference is defined as a
* static variable in the algorithm class.
*
* @param algorithmClass The given algorithm class
* @param The generic type of the algorithm's return value
* @return The type reference of the algorithm's return value as defined in the algorithm class
* @throws Exception if no type reference is defined in the algorithm class
*/
@SuppressWarnings("unchecked")
static public TypeReference getReturnType(Class extends Algorithm> algorithmClass) throws Exception {
try {
var declaredField = algorithmClass.getDeclaredField(RETURN_TYPE_FIELD_NAME);
return (TypeReference) declaredField.get(null);
} catch (NoSuchFieldException | IllegalAccessException exception) {
throw new Exception(UNDEFINED_TYPE_REFERENCE, algorithmClass);
}
}
/**
* This class is used for throwing specific exceptions while executing a protocol algorithm. The different types of
* algorithm exceptions are represented by the values of an internal enum class.
*/
static public final class Exception extends RuntimeException {
@SuppressWarnings("MissingJavadoc")
public enum Type {
INCOMPATIBLE_MATRIX,
INCOMPATIBLE_PARAMETERS,
INCOMPATIBLE_POINT,
INCOMPATIBLE_VALUES,
INSUFFICIENT_GROUP_SIZE,
NULL_POINTER,
PRECONDITION_FAILED,
SECURE_RANDOM_LOADING_FAILURE,
SERVICE_LOADING_PROBLEM,
UNDEFINED_TYPE_REFERENCE,
UNDEFINED_RUN_METHOD,
UNSUPPORTED_HASH_TYPE
}
/**
* The name of the algorithm causing this exception.
*/
private final String algorithmName;
/**
* The type of the exception.
*/
private final Type type;
/**
* Constructs a new algorithm exception for a given exception type.
*
* @param type The type of the exception
*/
public Exception(Type type) {
this(type, "");
}
/**
* Constructs a new algorithm exception for a given exception type based on the given parameters.
*
* @param type The type of the exception
* @param algorithmClass The class of the algorithm causing the exception
*/
public Exception(Type type, Class> algorithmClass) {
this(type, algorithmClass.getName());
}
/**
* Constructs a new algorithm exception for a given exception type based on the given parameters.
*
* @param type The type of the exception
* @param algorithmName The name of the algorithm causing the exception
*/
public Exception(Type type, String algorithmName) {
super(algorithmName.isEmpty() ? type.name() : algorithmName + ": " + type.name());
this.algorithmName = algorithmName;
this.type = type;
}
/**
* Returns the type of the exception.
*
* @return The type of the exception
*/
public Type getType() {
return this.type;
}
/**
* Returns the name of the algorithm causing this exception.
*
* @return The name of the algorithm causing this exception
*/
public String getAlgorithmName() {
return this.algorithmName;
}
}
/**
* This class provides two static methods for performing precondition tests with respect to algorithm parameters.
* The actual precondition tests are performed independently of this class, only the resulting boolean values are
* passed to the method {@link Precondition#check(boolean)}. The goal of this method is to collect the results of
* all possible precondition tests in one single place and to throw the same type of {@link Exception}.
*/
static public final class Precondition {
// private no-argument constructor to prevent the creation of instances of a utility class
private Precondition() {
}
/**
* Throws an {@link Exception} if the given boolean {@code b} is false.
*
* @param b A boolean value representing the result of a precondition test
*/
static public void check(boolean b) {
Precondition.check(b, Exception.Type.PRECONDITION_FAILED);
}
/**
* Throws an {@link Exception} if the given array of objects or one of the objects in the given array is
* {@code null}.
*
* @param objects The given objects
*/
@SuppressWarnings("DataFlowIssue")
static public void checkNotNull(Object... objects) {
Precondition.check(objects != null, Exception.Type.NULL_POINTER);
for (var object : objects) {
Precondition.check(object != null, Exception.Type.NULL_POINTER);
}
}
// private helper method for throwing an exception in case of a failed precondition
static private void check(boolean b, Exception.Type exceptionType) {
if (!b) {
var algorithmName = new java.lang.Exception().getStackTrace()[2].getClassName(); // gets the name of the calling class
throw new Exception(exceptionType, algorithmName);
}
}
}
}