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

package org.bouncycastle.pqc.crypto.slhdsa;

import org.bouncycastle.crypto.digests.SHAKEDigest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import java.io.IOException;
import org.bouncycastle.pqc.crypto.DigestUtils;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.params.ParametersWithContext;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import java.security.SecureRandom;
import org.bouncycastle.crypto.Signer;

public class HashSLHDSASigner implements Signer
{
    private byte[] msgPrefix;
    private SLHDSAPublicKeyParameters pubKey;
    private SLHDSAPrivateKeyParameters privKey;
    private SecureRandom random;
    private Digest digest;
    
    @Override
    public void init(final boolean b, CipherParameters parameters) {
        ParametersWithContext parametersWithContext = null;
        if (parameters instanceof ParametersWithContext) {
            parametersWithContext = (ParametersWithContext)parameters;
            parameters = ((ParametersWithContext)parameters).getParameters();
            if (parametersWithContext.getContextLength() > 255) {
                throw new IllegalArgumentException("context too long");
            }
        }
        SLHDSAParameters slhdsaParameters;
        if (b) {
            this.pubKey = null;
            if (parameters instanceof ParametersWithRandom) {
                this.privKey = (SLHDSAPrivateKeyParameters)((ParametersWithRandom)parameters).getParameters();
                this.random = ((ParametersWithRandom)parameters).getRandom();
            }
            else {
                this.privKey = (SLHDSAPrivateKeyParameters)parameters;
                this.random = null;
            }
            slhdsaParameters = this.privKey.getParameters();
        }
        else {
            this.pubKey = (SLHDSAPublicKeyParameters)parameters;
            this.privKey = null;
            this.random = null;
            slhdsaParameters = this.pubKey.getParameters();
        }
        this.initDigest(slhdsaParameters, parametersWithContext);
    }
    
    private void initDigest(final SLHDSAParameters slhdsaParameters, final ParametersWithContext parametersWithContext) {
        this.digest = createDigest(slhdsaParameters);
        final ASN1ObjectIdentifier digestOid = DigestUtils.getDigestOid(this.digest.getAlgorithmName());
        byte[] encoded;
        try {
            encoded = digestOid.getEncoded("DER");
        }
        catch (final IOException ex) {
            throw new IllegalStateException("oid encoding failed: " + ex.getMessage());
        }
        final int n = (parametersWithContext == null) ? 0 : parametersWithContext.getContextLength();
        (this.msgPrefix = new byte[2 + n + encoded.length])[0] = 1;
        this.msgPrefix[1] = (byte)n;
        if (parametersWithContext != null) {
            parametersWithContext.copyContextTo(this.msgPrefix, 2, n);
        }
        System.arraycopy(encoded, 0, this.msgPrefix, 2 + n, encoded.length);
    }
    
    @Override
    public void update(final byte b) {
        this.digest.update(b);
    }
    
    @Override
    public void update(final byte[] array, final int n, final int n2) {
        this.digest.update(array, n, n2);
    }
    
    @Override
    public byte[] generateSignature() throws CryptoException, DataLengthException {
        final SLHDSAEngine engine = this.privKey.getParameters().getEngine();
        engine.init(this.privKey.pk.seed);
        final byte[] array = new byte[this.digest.getDigestSize()];
        this.digest.doFinal(array, 0);
        final byte[] bytes = new byte[engine.N];
        if (this.random != null) {
            this.random.nextBytes(bytes);
        }
        else {
            System.arraycopy(this.privKey.pk.seed, 0, bytes, 0, bytes.length);
        }
        return internalGenerateSignature(this.privKey, this.msgPrefix, array, bytes);
    }
    
    @Override
    public boolean verifySignature(final byte[] array) {
        final byte[] array2 = new byte[this.digest.getDigestSize()];
        this.digest.doFinal(array2, 0);
        return internalVerifySignature(this.pubKey, this.msgPrefix, array2, array);
    }
    
    @Override
    public void reset() {
        this.digest.reset();
    }
    
    protected byte[] internalGenerateSignature(final byte[] array, final byte[] array2) {
        return internalGenerateSignature(this.privKey, null, array, array2);
    }
    
    private static byte[] internalGenerateSignature(final SLHDSAPrivateKeyParameters slhdsaPrivateKeyParameters, final byte[] array, final byte[] array2, final byte[] array3) {
        final SLHDSAEngine engine = slhdsaPrivateKeyParameters.getParameters().getEngine();
        engine.init(slhdsaPrivateKeyParameters.pk.seed);
        final Fors fors = new Fors(engine);
        final byte[] prf_msg = engine.PRF_msg(slhdsaPrivateKeyParameters.sk.prf, array3, array, array2);
        final IndexedDigest h_msg = engine.H_msg(prf_msg, slhdsaPrivateKeyParameters.pk.seed, slhdsaPrivateKeyParameters.pk.root, array, array2);
        final byte[] digest = h_msg.digest;
        final long idx_tree = h_msg.idx_tree;
        final int idx_leaf = h_msg.idx_leaf;
        final ADRS adrs = new ADRS();
        adrs.setTypeAndClear(3);
        adrs.setTreeAddress(idx_tree);
        adrs.setKeyPairAddress(idx_leaf);
        final SIG_FORS[] sign = fors.sign(digest, slhdsaPrivateKeyParameters.sk.seed, slhdsaPrivateKeyParameters.pk.seed, adrs);
        final ADRS adrs2 = new ADRS();
        adrs2.setTypeAndClear(3);
        adrs2.setTreeAddress(idx_tree);
        adrs2.setKeyPairAddress(idx_leaf);
        final byte[] pkFromSig = fors.pkFromSig(sign, digest, slhdsaPrivateKeyParameters.pk.seed, adrs2);
        new ADRS().setTypeAndClear(2);
        final byte[] sign2 = new HT(engine, slhdsaPrivateKeyParameters.getSeed(), slhdsaPrivateKeyParameters.getPublicSeed()).sign(pkFromSig, idx_tree, idx_leaf);
        final byte[][] array4 = new byte[sign.length + 2][];
        array4[0] = prf_msg;
        for (int i = 0; i != sign.length; ++i) {
            array4[1 + i] = Arrays.concatenate(sign[i].sk, Arrays.concatenate(sign[i].authPath));
        }
        array4[array4.length - 1] = sign2;
        return Arrays.concatenate(array4);
    }
    
    protected boolean internalVerifySignature(final byte[] array, final byte[] array2) {
        return internalVerifySignature(this.pubKey, null, array, array2);
    }
    
    private static boolean internalVerifySignature(final SLHDSAPublicKeyParameters slhdsaPublicKeyParameters, final byte[] array, final byte[] array2, final byte[] array3) {
        final SLHDSAEngine engine = slhdsaPublicKeyParameters.getParameters().getEngine();
        engine.init(slhdsaPublicKeyParameters.getSeed());
        final ADRS adrs = new ADRS();
        if ((1 + engine.K * (1 + engine.A) + engine.H + engine.D * engine.WOTS_LEN) * engine.N != array3.length) {
            return false;
        }
        final SIG sig = new SIG(engine.N, engine.K, engine.A, engine.D, engine.H_PRIME, engine.WOTS_LEN, array3);
        final byte[] r = sig.getR();
        final SIG_FORS[] sig_FORS = sig.getSIG_FORS();
        final SIG_XMSS[] sig_HT = sig.getSIG_HT();
        final IndexedDigest h_msg = engine.H_msg(r, slhdsaPublicKeyParameters.getSeed(), slhdsaPublicKeyParameters.getRoot(), array, array2);
        final byte[] digest = h_msg.digest;
        final long idx_tree = h_msg.idx_tree;
        final int idx_leaf = h_msg.idx_leaf;
        adrs.setTypeAndClear(3);
        adrs.setLayerAddress(0);
        adrs.setTreeAddress(idx_tree);
        adrs.setKeyPairAddress(idx_leaf);
        final byte[] pkFromSig = new Fors(engine).pkFromSig(sig_FORS, digest, slhdsaPublicKeyParameters.getSeed(), adrs);
        adrs.setTypeAndClear(2);
        adrs.setLayerAddress(0);
        adrs.setTreeAddress(idx_tree);
        adrs.setKeyPairAddress(idx_leaf);
        return new HT(engine, null, slhdsaPublicKeyParameters.getSeed()).verify(pkFromSig, sig_HT, slhdsaPublicKeyParameters.getSeed(), idx_tree, idx_leaf, slhdsaPublicKeyParameters.getRoot());
    }
    
    private static Digest createDigest(final SLHDSAParameters slhdsaParameters) {
        switch (slhdsaParameters.getType()) {
            case 0: {
                if (slhdsaParameters.getName().startsWith("sha2")) {
                    if (SLHDSAParameters.sha2_128f == slhdsaParameters || SLHDSAParameters.sha2_128s == slhdsaParameters) {
                        return SHA256Digest.newInstance();
                    }
                    return new SHA512Digest();
                }
                else {
                    if (SLHDSAParameters.shake_128f == slhdsaParameters || SLHDSAParameters.shake_128s == slhdsaParameters) {
                        return new SHAKEDigest(128);
                    }
                    return new SHAKEDigest(256);
                }
                break;
            }
            case 1: {
                return SHA256Digest.newInstance();
            }
            case 2: {
                return new SHA512Digest();
            }
            case 3: {
                return new SHAKEDigest(128);
            }
            case 4: {
                return new SHAKEDigest(256);
            }
            default: {
                throw new IllegalArgumentException("unknown parameters type");
            }
        }
    }
}
