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

package org.bouncycastle.pqc.crypto.util;

import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.pqc.crypto.ntru.NTRUKEMGenerator;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMGenerator;
import org.bouncycastle.crypto.EncapsulatedSecretGenerator;
import org.bouncycastle.pqc.crypto.ntru.NTRUKEMExtractor;
import org.bouncycastle.pqc.crypto.ntru.NTRUPrivateKeyParameters;
import org.bouncycastle.pqc.crypto.ntru.NTRUKeyGenerationParameters;
import org.bouncycastle.pqc.crypto.ntru.NTRUKeyPairGenerator;
import org.bouncycastle.pqc.crypto.ntru.NTRUParameters;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMExtractor;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyGenerationParameters;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyPairGenerator;
import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters;
import org.bouncycastle.pqc.crypto.KEMParameters;
import org.bouncycastle.crypto.EncapsulatedSecretExtractor;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import java.io.IOException;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import java.security.SecureRandom;
import org.bouncycastle.crypto.util.DEROtherInfo;

public class PQCOtherInfoGenerator
{
    protected final DEROtherInfo.Builder otherInfoBuilder;
    protected final SecureRandom random;
    protected boolean used;
    
    public PQCOtherInfoGenerator(final AlgorithmIdentifier algorithmIdentifier, final byte[] array, final byte[] array2, final SecureRandom random) {
        this.used = false;
        this.otherInfoBuilder = new DEROtherInfo.Builder(algorithmIdentifier, array, array2);
        this.random = random;
    }
    
    private static byte[] getEncoded(final AsymmetricKeyParameter asymmetricKeyParameter) {
        try {
            return SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(asymmetricKeyParameter).getEncoded();
        }
        catch (final IOException ex) {
            return null;
        }
    }
    
    private static AsymmetricKeyParameter getPublicKey(final byte[] array) throws IOException {
        return PublicKeyFactory.createKey(array);
    }
    
    public static class PartyU extends PQCOtherInfoGenerator
    {
        private AsymmetricCipherKeyPair aKp;
        private EncapsulatedSecretExtractor encSE;
        
        public PartyU(final KEMParameters kemParameters, final AlgorithmIdentifier algorithmIdentifier, final byte[] array, final byte[] array2, final SecureRandom secureRandom) {
            super(algorithmIdentifier, array, array2, secureRandom);
            if (kemParameters instanceof MLKEMParameters) {
                final MLKEMKeyPairGenerator mlkemKeyPairGenerator = new MLKEMKeyPairGenerator();
                mlkemKeyPairGenerator.init(new MLKEMKeyGenerationParameters(secureRandom, (MLKEMParameters)kemParameters));
                this.aKp = mlkemKeyPairGenerator.generateKeyPair();
                this.encSE = new MLKEMExtractor((MLKEMPrivateKeyParameters)this.aKp.getPrivate());
            }
            else {
                if (!(kemParameters instanceof NTRUParameters)) {
                    throw new IllegalArgumentException("unknown KEMParameters");
                }
                final NTRUKeyPairGenerator ntruKeyPairGenerator = new NTRUKeyPairGenerator();
                ntruKeyPairGenerator.init(new NTRUKeyGenerationParameters(secureRandom, (NTRUParameters)kemParameters));
                this.aKp = ntruKeyPairGenerator.generateKeyPair();
                this.encSE = new NTRUKEMExtractor((NTRUPrivateKeyParameters)this.aKp.getPrivate());
            }
        }
        
        public PQCOtherInfoGenerator withSuppPubInfo(final byte[] array) {
            this.otherInfoBuilder.withSuppPubInfo(array);
            return this;
        }
        
        public byte[] getSuppPrivInfoPartA() {
            return getEncoded(this.aKp.getPublic());
        }
        
        public DEROtherInfo generate(final byte[] array) {
            this.otherInfoBuilder.withSuppPrivInfo(this.encSE.extractSecret(array));
            return this.otherInfoBuilder.build();
        }
    }
    
    public static class PartyV extends PQCOtherInfoGenerator
    {
        private EncapsulatedSecretGenerator encSG;
        
        public PartyV(final KEMParameters kemParameters, final AlgorithmIdentifier algorithmIdentifier, final byte[] array, final byte[] array2, final SecureRandom secureRandom) {
            super(algorithmIdentifier, array, array2, secureRandom);
            if (kemParameters instanceof MLKEMParameters) {
                this.encSG = new MLKEMGenerator(secureRandom);
            }
            else {
                if (!(kemParameters instanceof NTRUParameters)) {
                    throw new IllegalArgumentException("unknown KEMParameters");
                }
                this.encSG = new NTRUKEMGenerator(secureRandom);
            }
        }
        
        public PQCOtherInfoGenerator withSuppPubInfo(final byte[] array) {
            this.otherInfoBuilder.withSuppPubInfo(array);
            return this;
        }
        
        public byte[] getSuppPrivInfoPartB(final byte[] array) {
            this.used = false;
            try {
                final SecretWithEncapsulation generateEncapsulated = this.encSG.generateEncapsulated(getPublicKey(array));
                this.otherInfoBuilder.withSuppPrivInfo(generateEncapsulated.getSecret());
                return generateEncapsulated.getEncapsulation();
            }
            catch (final IOException ex) {
                throw new IllegalArgumentException("cannot decode public key");
            }
        }
        
        public DEROtherInfo generate() {
            if (this.used) {
                throw new IllegalStateException("builder already used");
            }
            this.used = true;
            return this.otherInfoBuilder.build();
        }
    }
}
