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

ch.openchvote.algorithms.Algorithm Maven / Gradle / Ivy

Go to download

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> 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> 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);
            }
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy