/*
 * 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;

/**
 * Implementation of Maurer's PHI function for providing a Decryption proof.
 * 
 * @param <T>
 *            the {@link GroupElement} value type.
 */
public class PhiFunctionDecryption<T> extends PhiFunction<T> {

    /**
     * Creates an instance of {@code PhiFunctionDecryption}.
     * <P>
     * Note: the number of outputs and the computation rules are derived from
     * numInputs.
     * 
     * @param group
     *            the mathematical group on which this PHI function operates.
     * @param numInputs
     *            the number of secret inputs that the calculatePhi method of
     *            this class should accept.
     * @param baseElements
     *            a list of base elements which are members of the received
     *            mathematical group.
     * @throws GeneralCryptoLibException
     *             if arguments are invalid.
     */
    public <E extends GroupElement<T>> PhiFunctionDecryption(
            final MathematicalGroup<E> group, final int numInputs,
            final List<E> baseElements) throws GeneralCryptoLibException {

        super(group, numInputs, calculateNumOutputs(numInputs),
            baseElements,
            buildComputationRules(calculateNumOutputs(numInputs)));
    }

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

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

        for (int i = 0; i < numOutputs; i += 2) {

            rules[i] = new int[][] {{1, pairSecondValue } };
            rules[i + 1] = new int[][] {{2, pairSecondValue } };
            pairSecondValue++;
        }

        return rules;
    }

    private static int calculateNumOutputs(final int numberInputs) {
        return 2 * numberInputs;
    }
}
