// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.jcajce.provider.asymmetric.compositesignatures;

import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.digests.SHAKEDigest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import java.io.ByteArrayOutputStream;
import java.security.spec.PSSParameterSpec;
import java.security.spec.MGF1ParameterSpec;
import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import java.util.LinkedHashMap;
import org.bouncycastle.util.encoders.Hex;
import java.security.InvalidParameterException;
import org.bouncycastle.jcajce.util.SpecUtil;
import org.bouncycastle.jcajce.spec.CompositeSignatureSpec;
import java.security.SignatureException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchProviderException;
import java.security.NoSuchAlgorithmException;
import org.bouncycastle.jcajce.interfaces.BCKey;
import java.security.GeneralSecurityException;
import org.bouncycastle.util.Exceptions;
import java.security.Provider;
import org.bouncycastle.jcajce.CompositePrivateKey;
import java.security.PrivateKey;
import java.util.List;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.ASN1Primitive;
import java.security.InvalidKeyException;
import org.bouncycastle.jcajce.CompositePublicKey;
import java.security.PublicKey;
import org.bouncycastle.jcajce.util.BCJcaJceHelper;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import java.security.AlgorithmParameters;
import org.bouncycastle.jcajce.spec.ContextParameterSpec;
import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.crypto.Digest;
import java.security.Signature;
import java.security.Key;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import java.util.HashMap;
import java.util.Map;

public class SignatureSpi extends java.security.SignatureSpi
{
    private static final byte[] prefix;
    private static final Map<String, String> canonicalNames;
    private static final HashMap<ASN1ObjectIdentifier, byte[]> domainSeparators;
    private static final HashMap<ASN1ObjectIdentifier, AlgorithmParameterSpec> algorithmsParameterSpecs;
    private static final String ML_DSA_44 = "ML-DSA-44";
    private static final String ML_DSA_65 = "ML-DSA-65";
    private static final String ML_DSA_87 = "ML-DSA-87";
    private final SecureRandom random;
    private Key compositeKey;
    private final boolean isPrehash;
    private ASN1ObjectIdentifier algorithm;
    private String[] algs;
    private Signature[] componentSignatures;
    private byte[] domain;
    private Digest baseDigest;
    private JcaJceHelper helper;
    private Digest preHashDigest;
    private ContextParameterSpec contextSpec;
    private AlgorithmParameters engineParams;
    private boolean unprimed;
    
    SignatureSpi(final ASN1ObjectIdentifier asn1ObjectIdentifier, final Digest digest) {
        this(asn1ObjectIdentifier, digest, false);
    }
    
    SignatureSpi(final ASN1ObjectIdentifier asn1ObjectIdentifier, final Digest baseDigest, final boolean isPrehash) {
        this.random = CryptoServicesRegistrar.getSecureRandom();
        this.helper = new BCJcaJceHelper();
        this.engineParams = null;
        this.unprimed = true;
        this.algorithm = asn1ObjectIdentifier;
        this.isPrehash = isPrehash;
        if (asn1ObjectIdentifier != null) {
            this.baseDigest = baseDigest;
            this.preHashDigest = (isPrehash ? new NullDigest(baseDigest.getDigestSize()) : baseDigest);
            this.domain = SignatureSpi.domainSeparators.get(asn1ObjectIdentifier);
            this.algs = CompositeIndex.getPairing(asn1ObjectIdentifier);
            this.componentSignatures = new Signature[this.algs.length];
        }
    }
    
    @Override
    protected void engineInitVerify(final PublicKey compositeKey) throws InvalidKeyException {
        if (!(compositeKey instanceof CompositePublicKey)) {
            throw new InvalidKeyException("public key is not composite");
        }
        this.compositeKey = compositeKey;
        final CompositePublicKey compositePublicKey = (CompositePublicKey)this.compositeKey;
        if (this.algorithm != null) {
            if (!compositePublicKey.getAlgorithmIdentifier().getAlgorithm().equals(this.algorithm)) {
                throw new InvalidKeyException("provided composite public key cannot be used with the composite signature algorithm");
            }
        }
        else {
            final ASN1ObjectIdentifier algorithm = SubjectPublicKeyInfo.getInstance(compositeKey.getEncoded()).getAlgorithm().getAlgorithm();
            this.algorithm = algorithm;
            this.baseDigest = CompositeIndex.getDigest(algorithm);
            this.preHashDigest = (this.isPrehash ? new NullDigest(this.baseDigest.getDigestSize()) : this.baseDigest);
            this.domain = SignatureSpi.domainSeparators.get(algorithm);
            this.algs = CompositeIndex.getPairing(algorithm);
            this.componentSignatures = new Signature[this.algs.length];
        }
        this.createComponentSignatures(compositePublicKey.getPublicKeys(), compositePublicKey.getProviders());
        this.sigInitVerify();
    }
    
    private void sigInitVerify() throws InvalidKeyException {
        final CompositePublicKey compositePublicKey = (CompositePublicKey)this.compositeKey;
        for (int i = 0; i < this.componentSignatures.length; ++i) {
            this.componentSignatures[i].initVerify(compositePublicKey.getPublicKeys().get(i));
        }
        this.unprimed = true;
    }
    
    @Override
    protected void engineInitSign(final PrivateKey compositeKey) throws InvalidKeyException {
        if (!(compositeKey instanceof CompositePrivateKey)) {
            throw new InvalidKeyException("Private key is not composite.");
        }
        this.compositeKey = compositeKey;
        final CompositePrivateKey compositePrivateKey = (CompositePrivateKey)compositeKey;
        if (this.algorithm != null) {
            if (!compositePrivateKey.getAlgorithmIdentifier().getAlgorithm().equals(this.algorithm)) {
                throw new InvalidKeyException("provided composite public key cannot be used with the composite signature algorithm");
            }
        }
        else {
            final ASN1ObjectIdentifier algorithm = compositePrivateKey.getAlgorithmIdentifier().getAlgorithm();
            this.algorithm = algorithm;
            this.baseDigest = CompositeIndex.getDigest(algorithm);
            this.preHashDigest = (this.isPrehash ? new NullDigest(this.baseDigest.getDigestSize()) : this.baseDigest);
            this.domain = SignatureSpi.domainSeparators.get(algorithm);
            this.algs = CompositeIndex.getPairing(algorithm);
            this.componentSignatures = new Signature[this.algs.length];
        }
        this.createComponentSignatures(compositePrivateKey.getPrivateKeys(), compositePrivateKey.getProviders());
        this.sigInitSign();
    }
    
    private void createComponentSignatures(final List list, final List<Provider> list2) {
        try {
            if (list2 == null) {
                for (int i = 0; i != this.componentSignatures.length; ++i) {
                    this.componentSignatures[i] = this.getDefaultSignature(this.algs[i], list.get(i));
                }
            }
            else {
                for (int j = 0; j != this.componentSignatures.length; ++j) {
                    if (list2.get(j) == null) {
                        this.componentSignatures[j] = this.getDefaultSignature(this.algs[j], list.get(j));
                    }
                    else {
                        this.componentSignatures[j] = Signature.getInstance(this.algs[j], list2.get(j));
                    }
                }
            }
        }
        catch (final GeneralSecurityException ex) {
            throw Exceptions.illegalStateException(ex.getMessage(), ex);
        }
    }
    
    private Signature getDefaultSignature(final String algorithm, final Object o) throws NoSuchAlgorithmException, NoSuchProviderException {
        if (o instanceof BCKey) {
            return this.helper.createSignature(algorithm);
        }
        return Signature.getInstance(algorithm);
    }
    
    private void sigInitSign() throws InvalidKeyException {
        final CompositePrivateKey compositePrivateKey = (CompositePrivateKey)this.compositeKey;
        for (int i = 0; i < this.componentSignatures.length; ++i) {
            this.componentSignatures[i].initSign(compositePrivateKey.getPrivateKeys().get(i));
        }
        this.unprimed = true;
    }
    
    private void baseSigInit() throws SignatureException {
        try {
            this.componentSignatures[0].setParameter(new ContextParameterSpec(this.domain));
            final AlgorithmParameterSpec parameter = SignatureSpi.algorithmsParameterSpecs.get(this.algorithm);
            if (parameter != null) {
                this.componentSignatures[1].setParameter(parameter);
            }
        }
        catch (final InvalidAlgorithmParameterException ex) {
            throw new IllegalStateException("unable to set context on ML-DSA");
        }
        this.unprimed = false;
    }
    
    @Override
    protected void engineUpdate(final byte b) throws SignatureException {
        if (this.unprimed) {
            this.baseSigInit();
        }
        if (this.preHashDigest != null) {
            this.preHashDigest.update(b);
        }
        else {
            for (int i = 0; i < this.componentSignatures.length; ++i) {
                this.componentSignatures[i].update(b);
            }
        }
    }
    
    @Override
    protected void engineUpdate(final byte[] data, final int off, final int len) throws SignatureException {
        if (this.unprimed) {
            this.baseSigInit();
        }
        if (this.preHashDigest != null) {
            this.preHashDigest.update(data, off, len);
        }
        else {
            for (int i = 0; i < this.componentSignatures.length; ++i) {
                this.componentSignatures[i].update(data, off, len);
            }
        }
    }
    
    @Override
    protected byte[] engineSign() throws SignatureException {
        this.random.nextBytes(new byte[32]);
        if (this.preHashDigest != null) {
            this.processPreHashedMessage(null);
        }
        final byte[] sign = this.componentSignatures[0].sign();
        final byte[] sign2 = this.componentSignatures[1].sign();
        final byte[] array = new byte[sign.length + sign2.length];
        System.arraycopy(sign, 0, array, 0, sign.length);
        System.arraycopy(sign2, 0, array, sign.length, sign2.length);
        return array;
    }
    
    private void processPreHashedMessage(final byte[] data) throws SignatureException {
        final byte[] data2 = new byte[this.baseDigest.getDigestSize()];
        try {
            this.preHashDigest.doFinal(data2, 0);
        }
        catch (final IllegalStateException ex) {
            throw new SignatureException(ex.getMessage());
        }
        for (int i = 0; i < this.componentSignatures.length; ++i) {
            final Signature signature = this.componentSignatures[i];
            signature.update(SignatureSpi.prefix);
            signature.update(this.domain);
            if (this.contextSpec == null) {
                signature.update((byte)0);
            }
            else {
                final byte[] context = this.contextSpec.getContext();
                signature.update((byte)context.length);
                signature.update(context);
            }
            if (data != null) {
                signature.update(data, 0, data.length);
            }
            signature.update(data2, 0, data2.length);
        }
    }
    
    public static byte[][] splitCompositeSignature(final byte[] array, final int n) {
        final byte[] array2 = new byte[n];
        final byte[] array3 = new byte[array.length - n];
        System.arraycopy(array, 0, array2, 0, n);
        System.arraycopy(array, n, array3, 0, array3.length);
        return new byte[][] { array2, array3 };
    }
    
    @Override
    protected boolean engineVerify(final byte[] array) throws SignatureException {
        int n = 0;
        if (this.algs[0].indexOf("44") > 0) {
            n = 2420;
        }
        else if (this.algs[0].indexOf("65") > 0) {
            n = 3309;
        }
        else if (this.algs[0].indexOf("87") > 0) {
            n = 4627;
        }
        final byte[][] splitCompositeSignature = splitCompositeSignature(array, n);
        if (this.preHashDigest != null) {
            this.processPreHashedMessage(null);
        }
        boolean b = false;
        for (int i = 0; i < this.componentSignatures.length; ++i) {
            if (!this.componentSignatures[i].verify(splitCompositeSignature[i])) {
                b = true;
            }
        }
        return !b;
    }
    
    @Override
    protected void engineSetParameter(final AlgorithmParameterSpec algorithmParameterSpec) throws InvalidAlgorithmParameterException {
        if (!this.unprimed) {
            throw new InvalidAlgorithmParameterException("attempt to set parameter after update");
        }
        if (algorithmParameterSpec instanceof ContextParameterSpec) {
            this.contextSpec = (ContextParameterSpec)algorithmParameterSpec;
            try {
                if (this.compositeKey instanceof PublicKey) {
                    this.sigInitVerify();
                }
                else {
                    this.sigInitSign();
                }
                return;
            }
            catch (final InvalidKeyException cause) {
                throw new InvalidAlgorithmParameterException("keys invalid on reset: " + cause.getMessage(), cause);
            }
        }
        if (!(algorithmParameterSpec instanceof CompositeSignatureSpec)) {
            final byte[] context = SpecUtil.getContextFrom(algorithmParameterSpec);
            if (context != null) {
                this.contextSpec = new ContextParameterSpec(context);
                try {
                    if (this.compositeKey instanceof PublicKey) {
                        this.sigInitVerify();
                    }
                    else {
                        this.sigInitSign();
                    }
                }
                catch (final InvalidKeyException cause2) {
                    throw new InvalidAlgorithmParameterException("keys invalid on reset: " + cause2.getMessage(), cause2);
                }
            }
            throw new InvalidAlgorithmParameterException("unknown parameterSpec passed to composite signature");
        }
        final CompositeSignatureSpec compositeSignatureSpec = (CompositeSignatureSpec)algorithmParameterSpec;
        if (compositeSignatureSpec.isPrehashMode()) {
            this.preHashDigest = new NullDigest(this.baseDigest.getDigestSize());
        }
        else {
            this.preHashDigest = this.baseDigest;
        }
        final AlgorithmParameterSpec secondarySpec = compositeSignatureSpec.getSecondarySpec();
        if (secondarySpec == null || secondarySpec instanceof ContextParameterSpec) {
            this.contextSpec = (ContextParameterSpec)compositeSignatureSpec.getSecondarySpec();
        }
        else {
            final byte[] context2 = SpecUtil.getContextFrom(secondarySpec);
            if (context2 == null) {
                throw new InvalidAlgorithmParameterException("unknown parameterSpec passed to composite signature");
            }
            this.contextSpec = new ContextParameterSpec(context2);
        }
    }
    
    private String getCanonicalName(final String s) {
        final String s2 = SignatureSpi.canonicalNames.get(s);
        if (s2 != null) {
            return s2;
        }
        return s;
    }
    
    @Override
    protected void engineSetParameter(final String s, final Object o) throws InvalidParameterException {
        throw new UnsupportedOperationException("engineSetParameter unsupported");
    }
    
    @Override
    protected Object engineGetParameter(final String s) throws InvalidParameterException {
        throw new UnsupportedOperationException("engineGetParameter unsupported");
    }
    
    @Override
    protected final AlgorithmParameters engineGetParameters() {
        if (this.engineParams == null && this.contextSpec != null) {
            try {
                (this.engineParams = this.helper.createAlgorithmParameters("CONTEXT")).init(this.contextSpec);
            }
            catch (final Exception ex) {
                throw Exceptions.illegalStateException(ex.toString(), ex);
            }
        }
        return this.engineParams;
    }
    
    static {
        prefix = Hex.decode("436f6d706f73697465416c676f726974686d5369676e61747572657332303235");
        canonicalNames = new HashMap<String, String>();
        domainSeparators = new LinkedHashMap<ASN1ObjectIdentifier, byte[]>();
        algorithmsParameterSpecs = new HashMap<ASN1ObjectIdentifier, AlgorithmParameterSpec>();
        SignatureSpi.canonicalNames.put("MLDSA44", "ML-DSA-44");
        SignatureSpi.canonicalNames.put("MLDSA65", "ML-DSA-65");
        SignatureSpi.canonicalNames.put("MLDSA87", "ML-DSA-87");
        SignatureSpi.canonicalNames.put(NISTObjectIdentifiers.id_ml_dsa_44.getId(), "ML-DSA-44");
        SignatureSpi.canonicalNames.put(NISTObjectIdentifiers.id_ml_dsa_65.getId(), "ML-DSA-65");
        SignatureSpi.canonicalNames.put(NISTObjectIdentifiers.id_ml_dsa_87.getId(), "ML-DSA-87");
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, Hex.decode("434f4d505349472d4d4c44534134342d525341323034382d5053532d534841323536"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, Hex.decode("434f4d505349472d4d4c44534134342d525341323034382d504b435331352d534841323536"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, Hex.decode("434f4d505349472d4d4c44534134342d456432353531392d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, Hex.decode("434f4d505349472d4d4c44534134342d45434453412d503235362d534841323536"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d525341333037322d5053532d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d525341333037322d504b435331352d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d525341343039362d5053532d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d525341343039362d504b435331352d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d45434453412d503235362d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d45434453412d503338342d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d45434453412d42503235362d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d456432353531392d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d45434453412d42503338342d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, Hex.decode("434f4d505349472d4d4c44534138372d45643434382d5348414b45323536"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d525341333037322d5053532d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d525341343039362d5053532d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d45434453412d503338342d534841353132"));
        SignatureSpi.domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d45434453412d503532312d534841353132"));
        SignatureSpi.algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1));
        SignatureSpi.algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1));
        SignatureSpi.algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, new PSSParameterSpec("SHA-384", "MGF1", new MGF1ParameterSpec("SHA-384"), 48, 1));
        SignatureSpi.algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, new PSSParameterSpec("SHA-384", "MGF1", new MGF1ParameterSpec("SHA-384"), 48, 1));
        SignatureSpi.algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1));
    }
    
    public static final class COMPOSITE extends SignatureSpi
    {
        public COMPOSITE() {
            super(null, null, false);
        }
    }
    
    private static final class ErasableOutputStream extends ByteArrayOutputStream
    {
        public ErasableOutputStream() {
        }
        
        public byte[] getBuf() {
            return this.buf;
        }
    }
    
    public static final class MLDSA44_ECDSA_P256_SHA256 extends SignatureSpi
    {
        public MLDSA44_ECDSA_P256_SHA256() {
            super(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new SHA256Digest());
        }
    }
    
    public static final class MLDSA44_ECDSA_P256_SHA256_PREHASH extends SignatureSpi
    {
        public MLDSA44_ECDSA_P256_SHA256_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new SHA256Digest(), true);
        }
    }
    
    public static final class MLDSA44_Ed25519_SHA512 extends SignatureSpi
    {
        public MLDSA44_Ed25519_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA44_Ed25519_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA44_Ed25519_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA44_RSA2048_PKCS15_SHA256 extends SignatureSpi
    {
        public MLDSA44_RSA2048_PKCS15_SHA256() {
            super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new SHA256Digest());
        }
    }
    
    public static final class MLDSA44_RSA2048_PKCS15_SHA256_PREHASH extends SignatureSpi
    {
        public MLDSA44_RSA2048_PKCS15_SHA256_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new SHA256Digest(), true);
        }
    }
    
    public static final class MLDSA44_RSA2048_PSS_SHA256 extends SignatureSpi
    {
        public MLDSA44_RSA2048_PSS_SHA256() {
            super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new SHA256Digest());
        }
    }
    
    public static final class MLDSA44_RSA2048_PSS_SHA256_PREHASH extends SignatureSpi
    {
        public MLDSA44_RSA2048_PSS_SHA256_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new SHA256Digest(), true);
        }
    }
    
    public static final class MLDSA65_ECDSA_P256_SHA512 extends SignatureSpi
    {
        public MLDSA65_ECDSA_P256_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA65_ECDSA_P256_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA65_ECDSA_P256_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA65_ECDSA_P384_SHA512 extends SignatureSpi
    {
        public MLDSA65_ECDSA_P384_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA65_ECDSA_P384_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA65_ECDSA_P384_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA65_ECDSA_brainpoolP256r1_SHA512 extends SignatureSpi
    {
        public MLDSA65_ECDSA_brainpoolP256r1_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA65_ECDSA_brainpoolP256r1_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA65_ECDSA_brainpoolP256r1_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA65_Ed25519_SHA512 extends SignatureSpi
    {
        public MLDSA65_Ed25519_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA65_Ed25519_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA65_Ed25519_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA65_RSA3072_PKCS15_SHA512 extends SignatureSpi
    {
        public MLDSA65_RSA3072_PKCS15_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA65_RSA3072_PKCS15_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA65_RSA3072_PKCS15_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA65_RSA3072_PSS_SHA512 extends SignatureSpi
    {
        public MLDSA65_RSA3072_PSS_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA65_RSA3072_PSS_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA65_RSA3072_PSS_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA65_RSA4096_PKCS15_SHA512 extends SignatureSpi
    {
        public MLDSA65_RSA4096_PKCS15_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA65_RSA4096_PKCS15_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA65_RSA4096_PKCS15_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA65_RSA4096_PSS_SHA512 extends SignatureSpi
    {
        public MLDSA65_RSA4096_PSS_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA65_RSA4096_PSS_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA65_RSA4096_PSS_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA87_ECDSA_P384_SHA512 extends SignatureSpi
    {
        public MLDSA87_ECDSA_P384_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA87_ECDSA_P384_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA87_ECDSA_P384_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA87_ECDSA_P521_SHA512 extends SignatureSpi
    {
        public MLDSA87_ECDSA_P521_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA87_ECDSA_P521_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA87_ECDSA_P521_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA87_ECDSA_brainpoolP384r1_SHA512 extends SignatureSpi
    {
        public MLDSA87_ECDSA_brainpoolP384r1_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA87_ECDSA_brainpoolP384r1_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA87_ECDSA_brainpoolP384r1_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA87_Ed448_SHAKE256 extends SignatureSpi
    {
        public MLDSA87_Ed448_SHAKE256() {
            super(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, new SHAKEDigest(256));
        }
    }
    
    public static final class MLDSA87_Ed448_SHAKE256_PREHASH extends SignatureSpi
    {
        public MLDSA87_Ed448_SHAKE256_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, new SHAKEDigest(256), true);
        }
    }
    
    public static final class MLDSA87_RSA3072_PSS_SHA512 extends SignatureSpi
    {
        public MLDSA87_RSA3072_PSS_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA87_RSA3072_PSS_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA87_RSA3072_PSS_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, new SHA512Digest(), true);
        }
    }
    
    public static final class MLDSA87_RSA4096_PSS_SHA512 extends SignatureSpi
    {
        public MLDSA87_RSA4096_PSS_SHA512() {
            super(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, new SHA512Digest());
        }
    }
    
    public static final class MLDSA87_RSA4096_PSS_SHA512_PREHASH extends SignatureSpi
    {
        public MLDSA87_RSA4096_PSS_SHA512_PREHASH() {
            super(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, new SHA512Digest(), true);
        }
    }
    
    private static class NullDigest implements Digest
    {
        private final int expectedSize;
        private final OpenByteArrayOutputStream bOut;
        
        NullDigest(final int expectedSize) {
            this.bOut = new OpenByteArrayOutputStream();
            this.expectedSize = expectedSize;
        }
        
        @Override
        public String getAlgorithmName() {
            return "NULL";
        }
        
        @Override
        public int getDigestSize() {
            return this.bOut.size();
        }
        
        @Override
        public void update(final byte b) {
            this.bOut.write(b);
        }
        
        @Override
        public void update(final byte[] b, final int off, final int len) {
            this.bOut.write(b, off, len);
        }
        
        @Override
        public int doFinal(final byte[] array, final int n) {
            final int size = this.bOut.size();
            if (size != this.expectedSize) {
                throw new IllegalStateException("provided pre-hash digest is the wrong length");
            }
            this.bOut.copy(array, n);
            this.reset();
            return size;
        }
        
        @Override
        public void reset() {
            this.bOut.reset();
        }
        
        private static class OpenByteArrayOutputStream extends ByteArrayOutputStream
        {
            @Override
            public void reset() {
                super.reset();
                Arrays.clear(this.buf);
            }
            
            void copy(final byte[] array, final int n) {
                System.arraycopy(this.buf, 0, array, n, this.size());
            }
        }
    }
}
