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

package com.google.crypto.tink.hybrid;

import com.google.crypto.tink.internal.Util;
import com.google.crypto.tink.util.SecretBytes;
import java.math.BigInteger;
import com.google.crypto.tink.hybrid.internal.HpkeUtil;
import com.google.crypto.tink.internal.BigIntegerEncoding;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.ExtensionRegistryLite;
import com.google.crypto.tink.proto.KeyData;
import com.google.crypto.tink.proto.HpkeKeyFormat;
import com.google.crypto.tink.proto.KeyTemplate;
import javax.annotation.Nullable;
import com.google.crypto.tink.SecretKeyAccess;
import com.google.protobuf.ByteString;
import com.google.crypto.tink.proto.HpkeParams;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.internal.MutableSerializationRegistry;
import com.google.crypto.tink.proto.HpkeAead;
import com.google.crypto.tink.proto.HpkeKdf;
import com.google.crypto.tink.proto.HpkeKem;
import com.google.crypto.tink.proto.OutputPrefixType;
import com.google.crypto.tink.internal.EnumTypeProtoConverter;
import com.google.crypto.tink.internal.KeyParser;
import com.google.crypto.tink.internal.ProtoKeySerialization;
import com.google.crypto.tink.internal.KeySerializer;
import com.google.crypto.tink.internal.ParametersParser;
import com.google.crypto.tink.internal.ProtoParametersSerialization;
import com.google.crypto.tink.internal.ParametersSerializer;
import com.google.crypto.tink.util.Bytes;
import com.google.crypto.tink.AccessesPartialKey;

@AccessesPartialKey
public final class HpkeProtoSerialization
{
    private static final int VERSION = 0;
    private static final String PRIVATE_TYPE_URL = "type.googleapis.com/google.crypto.tink.HpkePrivateKey";
    private static final Bytes PRIVATE_TYPE_URL_BYTES;
    private static final String PUBLIC_TYPE_URL = "type.googleapis.com/google.crypto.tink.HpkePublicKey";
    private static final Bytes PUBLIC_TYPE_URL_BYTES;
    private static final ParametersSerializer<HpkeParameters, ProtoParametersSerialization> PARAMETERS_SERIALIZER;
    private static final ParametersParser<ProtoParametersSerialization> PARAMETERS_PARSER;
    private static final KeySerializer<HpkePublicKey, ProtoKeySerialization> PUBLIC_KEY_SERIALIZER;
    private static final KeyParser<ProtoKeySerialization> PUBLIC_KEY_PARSER;
    private static final KeySerializer<HpkePrivateKey, ProtoKeySerialization> PRIVATE_KEY_SERIALIZER;
    private static final KeyParser<ProtoKeySerialization> PRIVATE_KEY_PARSER;
    private static final EnumTypeProtoConverter<OutputPrefixType, HpkeParameters.Variant> VARIANT_TYPE_CONVERTER;
    private static final EnumTypeProtoConverter<HpkeKem, HpkeParameters.KemId> KEM_TYPE_CONVERTER;
    private static final EnumTypeProtoConverter<HpkeKdf, HpkeParameters.KdfId> KDF_TYPE_CONVERTER;
    private static final EnumTypeProtoConverter<HpkeAead, HpkeParameters.AeadId> AEAD_TYPE_CONVERTER;
    
    public static void register() throws GeneralSecurityException {
        register(MutableSerializationRegistry.globalInstance());
    }
    
    public static void register(final MutableSerializationRegistry registry) throws GeneralSecurityException {
        registry.registerParametersSerializer(HpkeProtoSerialization.PARAMETERS_SERIALIZER);
        registry.registerParametersParser(HpkeProtoSerialization.PARAMETERS_PARSER);
        registry.registerKeySerializer(HpkeProtoSerialization.PUBLIC_KEY_SERIALIZER);
        registry.registerKeyParser(HpkeProtoSerialization.PUBLIC_KEY_PARSER);
        registry.registerKeySerializer(HpkeProtoSerialization.PRIVATE_KEY_SERIALIZER);
        registry.registerKeyParser(HpkeProtoSerialization.PRIVATE_KEY_PARSER);
    }
    
    private static HpkeParams toProtoParameters(final HpkeParameters params) throws GeneralSecurityException {
        return HpkeParams.newBuilder().setKem(HpkeProtoSerialization.KEM_TYPE_CONVERTER.toProtoEnum(params.getKemId())).setKdf(HpkeProtoSerialization.KDF_TYPE_CONVERTER.toProtoEnum(params.getKdfId())).setAead(HpkeProtoSerialization.AEAD_TYPE_CONVERTER.toProtoEnum(params.getAeadId())).build();
    }
    
    private static com.google.crypto.tink.proto.HpkePublicKey toProtoPublicKey(final HpkePublicKey key) throws GeneralSecurityException {
        return com.google.crypto.tink.proto.HpkePublicKey.newBuilder().setVersion(0).setParams(toProtoParameters(key.getParameters())).setPublicKey(ByteString.copyFrom(key.getPublicKeyBytes().toByteArray())).build();
    }
    
    private static com.google.crypto.tink.proto.HpkePrivateKey toProtoPrivateKey(final HpkePrivateKey key, @Nullable final SecretKeyAccess access) throws GeneralSecurityException {
        return com.google.crypto.tink.proto.HpkePrivateKey.newBuilder().setVersion(0).setPublicKey(toProtoPublicKey(key.getPublicKey())).setPrivateKey(ByteString.copyFrom(key.getPrivateKeyBytes().toByteArray(SecretKeyAccess.requireAccess(access)))).build();
    }
    
    private static HpkeParameters fromProtoParameters(final OutputPrefixType outputPrefixType, final HpkeParams protoParams) throws GeneralSecurityException {
        return HpkeParameters.builder().setVariant(HpkeProtoSerialization.VARIANT_TYPE_CONVERTER.fromProtoEnum(outputPrefixType)).setKemId(HpkeProtoSerialization.KEM_TYPE_CONVERTER.fromProtoEnum(protoParams.getKem())).setKdfId(HpkeProtoSerialization.KDF_TYPE_CONVERTER.fromProtoEnum(protoParams.getKdf())).setAeadId(HpkeProtoSerialization.AEAD_TYPE_CONVERTER.fromProtoEnum(protoParams.getAead())).build();
    }
    
    private static ProtoParametersSerialization serializeParameters(final HpkeParameters parameters) throws GeneralSecurityException {
        return ProtoParametersSerialization.create(KeyTemplate.newBuilder().setTypeUrl("type.googleapis.com/google.crypto.tink.HpkePrivateKey").setValue(HpkeKeyFormat.newBuilder().setParams(toProtoParameters(parameters)).build().toByteString()).setOutputPrefixType(HpkeProtoSerialization.VARIANT_TYPE_CONVERTER.toProtoEnum(parameters.getVariant())).build());
    }
    
    private static ProtoKeySerialization serializePublicKey(final HpkePublicKey key, @Nullable final SecretKeyAccess access) throws GeneralSecurityException {
        return ProtoKeySerialization.create("type.googleapis.com/google.crypto.tink.HpkePublicKey", toProtoPublicKey(key).toByteString(), KeyData.KeyMaterialType.ASYMMETRIC_PUBLIC, HpkeProtoSerialization.VARIANT_TYPE_CONVERTER.toProtoEnum(key.getParameters().getVariant()), key.getIdRequirementOrNull());
    }
    
    private static ProtoKeySerialization serializePrivateKey(final HpkePrivateKey key, @Nullable final SecretKeyAccess access) throws GeneralSecurityException {
        return ProtoKeySerialization.create("type.googleapis.com/google.crypto.tink.HpkePrivateKey", toProtoPrivateKey(key, access).toByteString(), KeyData.KeyMaterialType.ASYMMETRIC_PRIVATE, HpkeProtoSerialization.VARIANT_TYPE_CONVERTER.toProtoEnum(key.getParameters().getVariant()), key.getIdRequirementOrNull());
    }
    
    private static HpkeParameters parseParameters(final ProtoParametersSerialization serialization) throws GeneralSecurityException {
        if (!serialization.getKeyTemplate().getTypeUrl().equals("type.googleapis.com/google.crypto.tink.HpkePrivateKey")) {
            throw new IllegalArgumentException("Wrong type URL in call to HpkeProtoSerialization.parseParameters: " + serialization.getKeyTemplate().getTypeUrl());
        }
        HpkeKeyFormat format;
        try {
            format = HpkeKeyFormat.parseFrom(serialization.getKeyTemplate().getValue(), ExtensionRegistryLite.getEmptyRegistry());
        }
        catch (final InvalidProtocolBufferException e) {
            throw new GeneralSecurityException("Parsing HpkeParameters failed: ", e);
        }
        return fromProtoParameters(serialization.getKeyTemplate().getOutputPrefixType(), format.getParams());
    }
    
    private static Bytes encodePublicKeyBytes(final HpkeParameters.KemId kemId, final byte[] publicKeyBytes) throws GeneralSecurityException {
        final BigInteger n = BigIntegerEncoding.fromUnsignedBigEndianBytes(publicKeyBytes);
        final byte[] encodedPublicKeyBytes = BigIntegerEncoding.toBigEndianBytesOfFixedLength(n, HpkeUtil.getEncodedPublicKeyLength(kemId));
        return Bytes.copyFrom(encodedPublicKeyBytes);
    }
    
    private static HpkePublicKey parsePublicKey(final ProtoKeySerialization serialization, @Nullable final SecretKeyAccess access) throws GeneralSecurityException {
        if (!serialization.getTypeUrl().equals("type.googleapis.com/google.crypto.tink.HpkePublicKey")) {
            throw new IllegalArgumentException("Wrong type URL in call to HpkeProtoSerialization.parsePublicKey: " + serialization.getTypeUrl());
        }
        try {
            final com.google.crypto.tink.proto.HpkePublicKey protoKey = com.google.crypto.tink.proto.HpkePublicKey.parseFrom(serialization.getValue(), ExtensionRegistryLite.getEmptyRegistry());
            if (protoKey.getVersion() != 0) {
                throw new GeneralSecurityException("Only version 0 keys are accepted");
            }
            final HpkeParameters params = fromProtoParameters(serialization.getOutputPrefixType(), protoKey.getParams());
            return HpkePublicKey.create(params, encodePublicKeyBytes(params.getKemId(), protoKey.getPublicKey().toByteArray()), serialization.getIdRequirementOrNull());
        }
        catch (final InvalidProtocolBufferException e) {
            throw new GeneralSecurityException("Parsing HpkePublicKey failed");
        }
    }
    
    private static SecretBytes encodePrivateKeyBytes(final HpkeParameters.KemId kemId, final byte[] privateKeyBytes, @Nullable final SecretKeyAccess access) throws GeneralSecurityException {
        final BigInteger n = BigIntegerEncoding.fromUnsignedBigEndianBytes(privateKeyBytes);
        final byte[] encodedPrivateKeyBytes = BigIntegerEncoding.toBigEndianBytesOfFixedLength(n, HpkeUtil.getEncodedPrivateKeyLength(kemId));
        return SecretBytes.copyFrom(encodedPrivateKeyBytes, SecretKeyAccess.requireAccess(access));
    }
    
    private static HpkePrivateKey parsePrivateKey(final ProtoKeySerialization serialization, @Nullable final SecretKeyAccess access) throws GeneralSecurityException {
        if (!serialization.getTypeUrl().equals("type.googleapis.com/google.crypto.tink.HpkePrivateKey")) {
            throw new IllegalArgumentException("Wrong type URL in call to HpkeProtoSerialization.parsePrivateKey: " + serialization.getTypeUrl());
        }
        try {
            final com.google.crypto.tink.proto.HpkePrivateKey protoKey = com.google.crypto.tink.proto.HpkePrivateKey.parseFrom(serialization.getValue(), ExtensionRegistryLite.getEmptyRegistry());
            if (protoKey.getVersion() != 0) {
                throw new GeneralSecurityException("Only version 0 keys are accepted");
            }
            final com.google.crypto.tink.proto.HpkePublicKey protoPublicKey = protoKey.getPublicKey();
            if (protoPublicKey.getVersion() != 0) {
                throw new GeneralSecurityException("Only version 0 keys are accepted");
            }
            final HpkeParameters params = fromProtoParameters(serialization.getOutputPrefixType(), protoPublicKey.getParams());
            final HpkePublicKey publicKey = HpkePublicKey.create(params, encodePublicKeyBytes(params.getKemId(), protoPublicKey.getPublicKey().toByteArray()), serialization.getIdRequirementOrNull());
            return HpkePrivateKey.create(publicKey, encodePrivateKeyBytes(params.getKemId(), protoKey.getPrivateKey().toByteArray(), access));
        }
        catch (final InvalidProtocolBufferException e) {
            throw new GeneralSecurityException("Parsing HpkePrivateKey failed");
        }
    }
    
    private HpkeProtoSerialization() {
    }
    
    static {
        PRIVATE_TYPE_URL_BYTES = Util.toBytesFromPrintableAscii("type.googleapis.com/google.crypto.tink.HpkePrivateKey");
        PUBLIC_TYPE_URL_BYTES = Util.toBytesFromPrintableAscii("type.googleapis.com/google.crypto.tink.HpkePublicKey");
        PARAMETERS_SERIALIZER = ParametersSerializer.create(HpkeProtoSerialization::serializeParameters, HpkeParameters.class, ProtoParametersSerialization.class);
        PARAMETERS_PARSER = ParametersParser.create(HpkeProtoSerialization::parseParameters, HpkeProtoSerialization.PRIVATE_TYPE_URL_BYTES, ProtoParametersSerialization.class);
        PUBLIC_KEY_SERIALIZER = KeySerializer.create(HpkeProtoSerialization::serializePublicKey, HpkePublicKey.class, ProtoKeySerialization.class);
        PUBLIC_KEY_PARSER = KeyParser.create(HpkeProtoSerialization::parsePublicKey, HpkeProtoSerialization.PUBLIC_TYPE_URL_BYTES, ProtoKeySerialization.class);
        PRIVATE_KEY_SERIALIZER = KeySerializer.create(HpkeProtoSerialization::serializePrivateKey, HpkePrivateKey.class, ProtoKeySerialization.class);
        PRIVATE_KEY_PARSER = KeyParser.create(HpkeProtoSerialization::parsePrivateKey, HpkeProtoSerialization.PRIVATE_TYPE_URL_BYTES, ProtoKeySerialization.class);
        VARIANT_TYPE_CONVERTER = EnumTypeProtoConverter.builder().add(OutputPrefixType.RAW, HpkeParameters.Variant.NO_PREFIX).add(OutputPrefixType.TINK, HpkeParameters.Variant.TINK).add(OutputPrefixType.LEGACY, HpkeParameters.Variant.CRUNCHY).add(OutputPrefixType.CRUNCHY, HpkeParameters.Variant.CRUNCHY).build();
        KEM_TYPE_CONVERTER = EnumTypeProtoConverter.builder().add(HpkeKem.DHKEM_P256_HKDF_SHA256, HpkeParameters.KemId.DHKEM_P256_HKDF_SHA256).add(HpkeKem.DHKEM_P384_HKDF_SHA384, HpkeParameters.KemId.DHKEM_P384_HKDF_SHA384).add(HpkeKem.DHKEM_P521_HKDF_SHA512, HpkeParameters.KemId.DHKEM_P521_HKDF_SHA512).add(HpkeKem.DHKEM_X25519_HKDF_SHA256, HpkeParameters.KemId.DHKEM_X25519_HKDF_SHA256).build();
        KDF_TYPE_CONVERTER = EnumTypeProtoConverter.builder().add(HpkeKdf.HKDF_SHA256, HpkeParameters.KdfId.HKDF_SHA256).add(HpkeKdf.HKDF_SHA384, HpkeParameters.KdfId.HKDF_SHA384).add(HpkeKdf.HKDF_SHA512, HpkeParameters.KdfId.HKDF_SHA512).build();
        AEAD_TYPE_CONVERTER = EnumTypeProtoConverter.builder().add(HpkeAead.AES_128_GCM, HpkeParameters.AeadId.AES_128_GCM).add(HpkeAead.AES_256_GCM, HpkeParameters.AeadId.AES_256_GCM).add(HpkeAead.CHACHA20_POLY1305, HpkeParameters.AeadId.CHACHA20_POLY1305).build();
    }
}
