/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.cryptolib.proofs.maurer.function;

import java.util.List;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.mathematical.groups.GroupElement;
import com.scytl.cryptolib.mathematical.groups.MathematicalGroup;

/**
 * The implementation of Maurer's PHI function used for generating the Zero
 * Knowledge Proof of Knowledge of the plaintext exponent equality.
 * 
 * @param <T>
 *            the type which parameterizes the group elements of the
 *            mathematical group.
 */
public final class PhiFunctionPlaintextExponentEquality<T> extends
        PhiFunction<T> {

    /**
     * Creates an instance of {@code PhiFunctionPlaintextExponentEquality}.
     * <P>
     * Note: the number of inputs is set to two, while the number of outputs and
     * the computation rules are derived from the length (size) of baseElements.
     * 
     * @param group
     *            the mathematical group.
     * @param baseElements
     *            the mathematical group elements used as base elements for the
     *            phi computation.
     * @throws GeneralCryptoLibException
     *             if arguments are invalid.
     */
    public <E extends GroupElement<T>> PhiFunctionPlaintextExponentEquality(
            final MathematicalGroup<E> group, final List<E> baseElements)
            throws GeneralCryptoLibException {

        super(
            group,
            2,
            calculateNumOutputs(baseElements.size()),
            baseElements,
            buildComputationRules(calculateNumOutputs(baseElements.size())));
    }

    private static int[][][] buildComputationRules(final int numOutputs) {

        int[][][] rules = new int[numOutputs][][];

        rules[0] = new int[][] {{1, 1 } };

        for (int i = 1; i < numOutputs; i++) {
            rules[i] =
                new int[][] { {i + 1, 1 }, {i + numOutputs, 2 } };
        }

        return rules;
    }

    private static int calculateNumOutputs(final int numBaseElements) {
        return ((numBaseElements - 1) / 2) + 1;
    }
}
