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

package org.bouncycastle.pqc.crypto.xmss;

import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.pqc.crypto.ExhaustedPrivateKeyException;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.pqc.crypto.StateAwareMessageSigner;

public class XMSSSigner implements StateAwareMessageSigner
{
    private XMSSPrivateKeyParameters privateKey;
    private XMSSPublicKeyParameters publicKey;
    private XMSSParameters params;
    private WOTSPlus wotsPlus;
    private KeyedHashFunctions khf;
    private boolean initSign;
    private boolean hasGenerated;
    
    @Override
    public void init(final boolean b, final CipherParameters cipherParameters) {
        if (b) {
            this.initSign = true;
            this.hasGenerated = false;
            this.privateKey = (XMSSPrivateKeyParameters)cipherParameters;
            this.params = this.privateKey.getParameters();
        }
        else {
            this.initSign = false;
            this.publicKey = (XMSSPublicKeyParameters)cipherParameters;
            this.params = this.publicKey.getParameters();
        }
        this.wotsPlus = this.params.getWOTSPlus();
        this.khf = this.wotsPlus.getKhf();
    }
    
    @Override
    public byte[] generateSignature(final byte[] array) {
        if (array == null) {
            throw new NullPointerException("message == null");
        }
        if (!this.initSign) {
            throw new IllegalStateException("signer not initialized for signature generation");
        }
        if (this.privateKey == null) {
            throw new IllegalStateException("signing key no longer usable");
        }
        synchronized (this.privateKey) {
            if (this.privateKey.getUsagesRemaining() <= 0L) {
                throw new ExhaustedPrivateKeyException("no usages of private key remaining");
            }
            if (this.privateKey.getBDSState().getAuthenticationPath().isEmpty()) {
                throw new IllegalStateException("not initialized");
            }
            try {
                final int index = this.privateKey.getIndex();
                this.hasGenerated = true;
                final byte[] prf = this.khf.PRF(this.privateKey.getSecretKeyPRF(), XMSSUtil.toBytesBigEndian(index, 32));
                return new XMSSSignature.Builder(this.params).withIndex(index).withRandom(prf).withWOTSPlusSignature(this.wotsSign(this.khf.HMsg(Arrays.concatenate(prf, this.privateKey.getRoot(), XMSSUtil.toBytesBigEndian(index, this.params.getTreeDigestSize())), array), (OTSHashAddress)new OTSHashAddress.Builder().withOTSAddress(index).build())).withAuthPath(this.privateKey.getBDSState().getAuthenticationPath()).build().toByteArray();
            }
            finally {
                this.privateKey.getBDSState().markUsed();
                this.privateKey.rollKey();
            }
        }
    }
    
    public long getUsagesRemaining() {
        return this.privateKey.getUsagesRemaining();
    }
    
    @Override
    public boolean verifySignature(final byte[] array, final byte[] array2) {
        final XMSSSignature build = new XMSSSignature.Builder(this.params).withSignature(array2).build();
        final int index = build.getIndex();
        this.wotsPlus.importKeys(new byte[this.params.getTreeDigestSize()], this.publicKey.getPublicSeed());
        final byte[] hMsg = this.khf.HMsg(Arrays.concatenate(build.getRandom(), this.publicKey.getRoot(), XMSSUtil.toBytesBigEndian(index, this.params.getTreeDigestSize())), array);
        final int height = this.params.getHeight();
        return Arrays.constantTimeAreEqual(XMSSVerifierUtil.getRootNodeFromSignature(this.wotsPlus, height, hMsg, build, (OTSHashAddress)new OTSHashAddress.Builder().withOTSAddress(index).build(), XMSSUtil.getLeafIndex(index, height)).getValue(), this.publicKey.getRoot());
    }
    
    @Override
    public AsymmetricKeyParameter getUpdatedPrivateKey() {
        synchronized (this.privateKey) {
            if (this.hasGenerated) {
                final XMSSPrivateKeyParameters privateKey = this.privateKey;
                this.privateKey = null;
                return privateKey;
            }
            final XMSSPrivateKeyParameters privateKey2 = this.privateKey;
            if (privateKey2 != null) {
                this.privateKey = this.privateKey.getNextKey();
            }
            return privateKey2;
        }
    }
    
    private WOTSPlusSignature wotsSign(final byte[] array, final OTSHashAddress otsHashAddress) {
        if (array.length != this.params.getTreeDigestSize()) {
            throw new IllegalArgumentException("size of messageDigest needs to be equal to size of digest");
        }
        if (otsHashAddress == null) {
            throw new NullPointerException("otsHashAddress == null");
        }
        this.wotsPlus.importKeys(this.wotsPlus.getWOTSPlusSecretKey(this.privateKey.getSecretKeySeed(), otsHashAddress), this.privateKey.getPublicSeed());
        return this.wotsPlus.sign(array, otsHashAddress);
    }
}
