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

package org.bouncycastle.pqc.crypto.sphincsplus;

import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.CipherParameters;
import java.security.SecureRandom;
import org.bouncycastle.pqc.crypto.MessageSigner;

public class SPHINCSPlusSigner implements MessageSigner
{
    private SPHINCSPlusPrivateKeyParameters privKey;
    private SPHINCSPlusPublicKeyParameters pubKey;
    private SecureRandom random;
    
    @Override
    public void init(final boolean b, final CipherParameters cipherParameters) {
        if (b) {
            if (cipherParameters instanceof ParametersWithRandom) {
                this.privKey = (SPHINCSPlusPrivateKeyParameters)((ParametersWithRandom)cipherParameters).getParameters();
                this.random = ((ParametersWithRandom)cipherParameters).getRandom();
            }
            else {
                this.privKey = (SPHINCSPlusPrivateKeyParameters)cipherParameters;
            }
        }
        else {
            this.pubKey = (SPHINCSPlusPublicKeyParameters)cipherParameters;
        }
    }
    
    @Override
    public byte[] generateSignature(final byte[] array) {
        final SPHINCSPlusEngine engine = this.privKey.getParameters().getEngine();
        engine.init(this.privKey.pk.seed);
        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);
        }
        final Fors fors = new Fors(engine);
        final byte[] prf_msg = engine.PRF_msg(this.privKey.sk.prf, bytes, array);
        final IndexedDigest h_msg = engine.H_msg(prf_msg, this.privKey.pk.seed, this.privKey.pk.root, array);
        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, this.privKey.sk.seed, this.privKey.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, this.privKey.pk.seed, adrs2);
        new ADRS().setTypeAndClear(2);
        final byte[] sign2 = new HT(engine, this.privKey.getSeed(), this.privKey.getPublicSeed()).sign(pkFromSig, idx_tree, idx_leaf);
        final byte[][] array2 = new byte[sign.length + 2][];
        array2[0] = prf_msg;
        for (int i = 0; i != sign.length; ++i) {
            array2[1 + i] = Arrays.concatenate(sign[i].sk, Arrays.concatenate(sign[i].authPath));
        }
        array2[array2.length - 1] = sign2;
        return Arrays.concatenate(array2);
    }
    
    @Override
    public boolean verifySignature(final byte[] array, final byte[] array2) {
        final SPHINCSPlusEngine engine = this.pubKey.getParameters().getEngine();
        engine.init(this.pubKey.getSeed());
        final ADRS adrs = new ADRS();
        final SIG sig = new SIG(engine.N, engine.K, engine.A, engine.D, engine.H_PRIME, engine.WOTS_LEN, array2);
        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, this.pubKey.getSeed(), this.pubKey.getRoot(), array);
        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, this.pubKey.getSeed(), adrs);
        adrs.setTypeAndClear(2);
        adrs.setLayerAddress(0);
        adrs.setTreeAddress(idx_tree);
        adrs.setKeyPairAddress(idx_leaf);
        return new HT(engine, null, this.pubKey.getSeed()).verify(pkFromSig, sig_HT, this.pubKey.getSeed(), idx_tree, idx_leaf, this.pubKey.getRoot());
    }
}
