/*******************************************************************************
 * Copyright (C) 2026, Leo Galambos
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. All advertising materials mentioning features or use of this software must
 *    display the following acknowledgement:
 *    This product includes software developed by the Egothor project.
 *
 * 4. Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/
package zeroecho.core.alg.elgamal;

import java.math.BigInteger;
import java.util.Objects;

import org.bouncycastle.jce.spec.ElGamalParameterSpec;

import zeroecho.core.annotation.Describable;
import zeroecho.core.spec.AlgorithmKeySpec;

/**
 * <h2>ElGamal Parameter Specification</h2>
 *
 * Wrapper for ElGamal domain parameters {@code (p, g)}. Unlike
 * {@link ElgamalKeyGenSpec}, which requests new random primes,
 * {@code ElgamalParamSpec} directly encapsulates an explicit safe prime modulus
 * and generator.
 *
 * <p>
 * An {@link ElGamalParameterSpec} instance defines the cyclic subgroup of
 * integers modulo {@code p}, generated by {@code g}, in which all ElGamal
 * operations occur. The modulus {@code p} should be a large safe prime to
 * resist discrete logarithm attacks.
 * </p>
 *
 * <h2>Contents</h2>
 * <ul>
 * <li>{@link #parameters()} exposes the wrapped BouncyCastle
 * {@link org.bouncycastle.jce.spec.ElGamalParameterSpec} object.</li>
 * <li>{@link #keySize()} reports the bit length of the modulus {@code p}.</li>
 * </ul>
 *
 * <h2>Predefined parameters</h2>
 * <ul>
 * <li>{@link #ffdhe2048()} returns the 2048-bit safe prime from
 * <a href="https://www.rfc-editor.org/rfc/rfc7919.html">RFC 7919</a>
 * (FFDHE2048), with generator {@code g = 2}. This provides a widely accepted
 * interoperable parameter set.</li>
 * </ul>
 *
 * <h2>Usage</h2> <pre>{@code
 * ElgamalParamSpec spec = ElgamalParamSpec.ffdhe2048();
 * KeyPair kp = algo.asymmetricKeyPairGenerator(ElgamalParamSpec.class).generateKeyPair(spec);
 * }</pre>
 *
 * <h2>Thread-safety</h2> Instances are immutable and safe to share between
 * threads.
 *
 * @since 1.0
 */
public final class ElgamalParamSpec implements AlgorithmKeySpec, Describable {
    private final ElGamalParameterSpec params;
    private final int bits;

    /**
     * Creates a new ElGamal parameter spec with modulus and generator.
     *
     * @param p safe prime modulus (must not be {@code null})
     * @param g generator of the subgroup (must not be {@code null})
     * @throws NullPointerException if either argument is {@code null}
     */
    public ElgamalParamSpec(BigInteger p, BigInteger g) {
        Objects.requireNonNull(p, "p");
        Objects.requireNonNull(g, "g");
        this.params = new ElGamalParameterSpec(p, g);
        this.bits = p.bitLength();
    }

    /**
     * Returns the underlying ElGamal parameters.
     *
     * @return {@link ElGamalParameterSpec} wrapping {@code (p, g)}
     */
    public ElGamalParameterSpec parameters() {
        return params;
    }

    /**
     * Returns the modulus size in bits.
     *
     * @return number of bits of {@code p}
     */
    public int keySize() {
        return bits;
    }

    /**
     * Returns the RFC 7919 FFDHE2048 safe prime with generator 2.
     *
     * <p>
     * This parameter set is standardized and widely supported for Diffie–Hellman
     * and ElGamal constructions.
     * </p>
     *
     * @return predefined ElGamal parameter spec (2048-bit, g=2)
     */
    public static ElgamalParamSpec ffdhe2048() {
        final String pHex = """
                    FFFFFFFF FFFFFFFF ADF85458 A2BB4A9A AFDC5620 273D3CF1
                    D8B9C583 CE2D3695 A9E13641 146433FB CC939DCE 249B3EF9
                    7D2FE363 630C75D8 F681B202 AEC4617A D3DF1ED5 D5FD6561
                    2433F51F 5F066ED0 85636555 3DED1AF3 B557135E 7F57C935
                    984F0C70 E0E68B77 E2A689DA F3EFE872 1DF158A1 36ADE735
                    30ACCA4F 483A797A BC0AB182 B324FB61 D108A94B B2C8E3FB
                    B96ADAB7 60D7F468 1D4F42A3 DE394DF4 AE56EDE7 6372BB19
                    0B07A7C8 EE0A6D70 9E02FCE1 CDF7E2EC C03404CD 28342F61
                    9172FE9C E98583FF 8E4F1232 EEF28183 C3FE3B1B 4C6FAD73
                    3BB5FCBC 2EC22005 C58EF183 7D1683B2 C6F34A26 C1B2EFFA
                    886B4238 61285C97 FFFFFFFF FFFFFFFF
                """.replaceAll("\\s+", "");
        BigInteger p = new BigInteger(pHex, 16);
        BigInteger g = BigInteger.valueOf(2L);
        return new ElgamalParamSpec(p, g);
    }

    /**
     * Human-readable description of this spec.
     *
     * <p>
     * Example: {@code "predefined(p=2048, g=2)"}.
     * </p>
     *
     * @return descriptive string including modulus size and generator
     */
    @Override
    public String description() {
        return "predefined(p=" + bits + ", g=2)";
    }
}
