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

package com.google.crypto.tink.signature.internal;

import java.security.spec.EncodedKeySpec;
import java.security.Signature;
import com.google.crypto.tink.internal.Util;
import com.google.crypto.tink.internal.ConscryptUtil;
import com.google.crypto.tink.AccessesPartialKey;
import java.security.spec.KeySpec;
import java.security.KeyFactory;
import com.google.crypto.tink.signature.MlDsaParameters;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.signature.MlDsaPublicKey;
import java.security.Provider;
import java.security.PublicKey;
import com.google.crypto.tink.config.internal.TinkFipsUtil;
import com.google.errorprone.annotations.Immutable;
import com.google.crypto.tink.PublicKeyVerify;

@Immutable
public final class MlDsaVerifyConscrypt implements PublicKeyVerify
{
    public static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS;
    static final int ML_DSA_65_SIG_LENGTH = 3309;
    static final String ML_DSA_65_ALGORITHM = "ML-DSA-65";
    private final byte[] outputPrefix;
    private final PublicKey publicKey;
    private final String algorithm;
    private final int signatureLength;
    private final Provider provider;
    
    private MlDsaVerifyConscrypt(final byte[] outputPrefix, final PublicKey publicKey, final String algorithm, final int signatureLength, final Provider provider) {
        this.outputPrefix = outputPrefix;
        this.publicKey = publicKey;
        this.algorithm = algorithm;
        this.signatureLength = signatureLength;
        this.provider = provider;
    }
    
    @AccessesPartialKey
    public static PublicKeyVerify createWithProvider(final MlDsaPublicKey mlDsaPublicKey, final Provider provider) throws GeneralSecurityException {
        if (provider == null) {
            throw new NullPointerException("provider must not be null");
        }
        if (!MlDsaVerifyConscrypt.FIPS.isCompatible()) {
            throw new GeneralSecurityException("Can not use ML-DSA in FIPS-mode, as it is not yet certified in Conscrypt.");
        }
        final MlDsaParameters.MlDsaInstance mlDsaInstance = mlDsaPublicKey.getParameters().getMlDsaInstance();
        if (mlDsaInstance != MlDsaParameters.MlDsaInstance.ML_DSA_65) {
            throw new GeneralSecurityException("Only ML-DSA-65 currently supported");
        }
        final PublicKey publicKey = KeyFactory.getInstance("ML-DSA-65", provider).generatePublic(new RawKeySpec(mlDsaPublicKey.getSerializedPublicKey().toByteArray()));
        return new MlDsaVerifyConscrypt(mlDsaPublicKey.getOutputPrefix().toByteArray(), publicKey, "ML-DSA-65", 3309, provider);
    }
    
    @AccessesPartialKey
    public static PublicKeyVerify create(final MlDsaPublicKey mlDsaPublicKey) throws GeneralSecurityException {
        if (!MlDsaVerifyConscrypt.FIPS.isCompatible()) {
            throw new GeneralSecurityException("Can not use ML-DSA in FIPS-mode, as it is not yet certified in Conscrypt.");
        }
        final Provider provider = ConscryptUtil.providerOrNull();
        if (provider == null) {
            throw new GeneralSecurityException("Obtaining Conscrypt provider failed");
        }
        return createWithProvider(mlDsaPublicKey, provider);
    }
    
    @Override
    public void verify(final byte[] signature, final byte[] data) throws GeneralSecurityException {
        if (!Util.isPrefix(this.outputPrefix, signature)) {
            throw new GeneralSecurityException("Invalid signature (output prefix mismatch)");
        }
        if (signature.length != this.outputPrefix.length + this.signatureLength) {
            throw new GeneralSecurityException("Invalid signature length");
        }
        final Signature verifier = Signature.getInstance(this.algorithm, this.provider);
        verifier.initVerify(this.publicKey);
        verifier.update(data);
        if (!verifier.verify(signature, this.outputPrefix.length, this.signatureLength)) {
            throw new GeneralSecurityException("Invalid signature");
        }
    }
    
    public static boolean isSupported() {
        if (!MlDsaVerifyConscrypt.FIPS.isCompatible()) {
            return false;
        }
        final Provider provider = ConscryptUtil.providerOrNull();
        if (provider == null) {
            return false;
        }
        try {
            final KeyFactory unusedKeyFactory = KeyFactory.getInstance("ML-DSA-65", provider);
            final Signature unusedSignature = Signature.getInstance("ML-DSA-65", provider);
            return true;
        }
        catch (final GeneralSecurityException e) {
            return false;
        }
    }
    
    static {
        FIPS = TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS;
    }
    
    public static final class RawKeySpec extends EncodedKeySpec
    {
        public RawKeySpec(final byte[] encoded) {
            super(encoded);
        }
        
        @Override
        public String getFormat() {
            return "raw";
        }
    }
}
