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

package com.google.crypto.tink.signature;

import java.util.Iterator;
import com.google.crypto.tink.signature.internal.LegacyFullVerify;
import com.google.crypto.tink.internal.PrimitiveRegistry;
import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
import com.google.crypto.tink.internal.MonitoringClient;
import com.google.crypto.tink.internal.MonitoringUtil;
import com.google.crypto.tink.internal.MutableMonitoringRegistry;
import com.google.crypto.tink.KeyStatus;
import com.google.crypto.tink.internal.PrefixMap;
import com.google.crypto.tink.internal.MonitoringAnnotations;
import com.google.crypto.tink.internal.KeysetHandleInterface;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.util.Bytes;
import com.google.crypto.tink.Key;
import com.google.crypto.tink.internal.LegacyProtoKey;
import com.google.crypto.tink.internal.PrimitiveConstructor;
import com.google.crypto.tink.PublicKeyVerify;
import com.google.crypto.tink.internal.PrimitiveWrapper;

public class PublicKeyVerifyWrapper implements PrimitiveWrapper<PublicKeyVerify, PublicKeyVerify>
{
    private static final PublicKeyVerifyWrapper WRAPPER;
    private static final PrimitiveConstructor<LegacyProtoKey, PublicKeyVerify> LEGACY_PRIMITIVE_CONSTRUCTOR;
    
    private static Bytes getOutputPrefix(final Key key) throws GeneralSecurityException {
        if (key instanceof SignaturePublicKey) {
            return ((SignaturePublicKey)key).getOutputPrefix();
        }
        if (key instanceof LegacyProtoKey) {
            return ((LegacyProtoKey)key).getOutputPrefix();
        }
        throw new GeneralSecurityException("Cannot get output prefix for key of class " + key.getClass().getName() + " with parameters " + key.getParameters());
    }
    
    @Override
    public PublicKeyVerify wrap(final KeysetHandleInterface keysetHandle, final MonitoringAnnotations annotations, final PrimitiveFactory<PublicKeyVerify> factory) throws GeneralSecurityException {
        final PrefixMap.Builder<PublicKeyVerifyWithId> builder = new PrefixMap.Builder<PublicKeyVerifyWithId>();
        for (int i = 0; i < keysetHandle.size(); ++i) {
            final KeysetHandleInterface.Entry entry = keysetHandle.getAt(i);
            if (entry.getStatus().equals(KeyStatus.ENABLED)) {
                final PublicKeyVerify publicKeyVerify = factory.create(entry);
                builder.put(getOutputPrefix(entry.getKey()), new PublicKeyVerifyWithId(publicKeyVerify, entry.getId()));
            }
        }
        MonitoringClient.Logger logger;
        if (!annotations.isEmpty()) {
            final MonitoringClient client = MutableMonitoringRegistry.globalInstance().getMonitoringClient();
            logger = client.createLogger(keysetHandle, annotations, "public_key_verify", "verify");
        }
        else {
            logger = MonitoringUtil.DO_NOTHING_LOGGER;
        }
        return new WrappedPublicKeyVerify(builder.build(), logger);
    }
    
    @Override
    public Class<PublicKeyVerify> getPrimitiveClass() {
        return PublicKeyVerify.class;
    }
    
    @Override
    public Class<PublicKeyVerify> getInputPrimitiveClass() {
        return PublicKeyVerify.class;
    }
    
    static void register() throws GeneralSecurityException {
        MutablePrimitiveRegistry.globalInstance().registerPrimitiveWrapper((PrimitiveWrapper<Object, Object>)PublicKeyVerifyWrapper.WRAPPER);
        MutablePrimitiveRegistry.globalInstance().registerPrimitiveConstructor(PublicKeyVerifyWrapper.LEGACY_PRIMITIVE_CONSTRUCTOR);
    }
    
    public static void registerToInternalPrimitiveRegistry(final PrimitiveRegistry.Builder primitiveRegistryBuilder) throws GeneralSecurityException {
        primitiveRegistryBuilder.registerPrimitiveWrapper((PrimitiveWrapper<Object, Object>)PublicKeyVerifyWrapper.WRAPPER);
    }
    
    static {
        WRAPPER = new PublicKeyVerifyWrapper();
        LEGACY_PRIMITIVE_CONSTRUCTOR = PrimitiveConstructor.create(LegacyFullVerify::create, LegacyProtoKey.class, PublicKeyVerify.class);
    }
    
    private static class PublicKeyVerifyWithId
    {
        public final PublicKeyVerify publicKeyVerify;
        public final int id;
        
        public PublicKeyVerifyWithId(final PublicKeyVerify publicKeyVerify, final int id) {
            this.publicKeyVerify = publicKeyVerify;
            this.id = id;
        }
    }
    
    private static class WrappedPublicKeyVerify implements PublicKeyVerify
    {
        private final PrefixMap<PublicKeyVerifyWithId> allPublicKeyVerifys;
        private final MonitoringClient.Logger monitoringLogger;
        
        public WrappedPublicKeyVerify(final PrefixMap<PublicKeyVerifyWithId> allPublicKeyVerifys, final MonitoringClient.Logger monitoringLogger) {
            this.allPublicKeyVerifys = allPublicKeyVerifys;
            this.monitoringLogger = monitoringLogger;
        }
        
        @Override
        public void verify(final byte[] signature, final byte[] data) throws GeneralSecurityException {
            for (final PublicKeyVerifyWithId publicKeyVerifyWithId : this.allPublicKeyVerifys.getAllWithMatchingPrefix(signature)) {
                try {
                    publicKeyVerifyWithId.publicKeyVerify.verify(signature, data);
                    this.monitoringLogger.log(publicKeyVerifyWithId.id, data.length);
                    return;
                }
                catch (final GeneralSecurityException ex) {
                    continue;
                }
                break;
            }
            this.monitoringLogger.logFailure();
            throw new GeneralSecurityException("invalid signature");
        }
    }
}
