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

package org.bouncycastle.pqc.crypto.lms;

import org.bouncycastle.pqc.crypto.ExhaustedPrivateKeyException;
import org.bouncycastle.util.io.Streams;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.WeakHashMap;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.Digest;
import java.util.Map;

public class LMSPrivateKeyParameters extends LMSKeyParameters implements LMSContextBasedSigner
{
    private static CacheKey T1;
    private static CacheKey[] internedKeys;
    private final byte[] I;
    private final LMSigParameters parameters;
    private final LMOtsParameters otsParameters;
    private final int maxQ;
    private final byte[] masterSecret;
    private final Map<CacheKey, byte[]> tCache;
    private final int maxCacheR;
    private final Digest tDigest;
    private int q;
    private LMSPublicKeyParameters publicKey;
    
    public LMSPrivateKeyParameters(final LMSigParameters parameters, final LMOtsParameters otsParameters, final int q, final byte[] array, final int maxQ, final byte[] array2) {
        super(true);
        this.parameters = parameters;
        this.otsParameters = otsParameters;
        this.q = q;
        this.I = Arrays.clone(array);
        this.maxQ = maxQ;
        this.masterSecret = Arrays.clone(array2);
        this.maxCacheR = 1 << this.parameters.getH() + 1;
        this.tCache = new WeakHashMap<CacheKey, byte[]>();
        this.tDigest = DigestUtil.getDigest(parameters);
    }
    
    private LMSPrivateKeyParameters(final LMSPrivateKeyParameters lmsPrivateKeyParameters, final int q, final int maxQ) {
        super(true);
        this.parameters = lmsPrivateKeyParameters.parameters;
        this.otsParameters = lmsPrivateKeyParameters.otsParameters;
        this.q = q;
        this.I = lmsPrivateKeyParameters.I;
        this.maxQ = maxQ;
        this.masterSecret = lmsPrivateKeyParameters.masterSecret;
        this.maxCacheR = 1 << this.parameters.getH();
        this.tCache = lmsPrivateKeyParameters.tCache;
        this.tDigest = DigestUtil.getDigest(this.parameters);
        this.publicKey = lmsPrivateKeyParameters.publicKey;
    }
    
    public static LMSPrivateKeyParameters getInstance(final byte[] array, final byte[] array2) throws IOException {
        final LMSPrivateKeyParameters instance = getInstance(array);
        instance.publicKey = LMSPublicKeyParameters.getInstance(array2);
        return instance;
    }
    
    public static LMSPrivateKeyParameters getInstance(final Object obj) throws IOException {
        if (obj instanceof LMSPrivateKeyParameters) {
            return (LMSPrivateKeyParameters)obj;
        }
        if (obj instanceof DataInputStream) {
            final DataInputStream dataInputStream = (DataInputStream)obj;
            if (dataInputStream.readInt() != 0) {
                throw new IllegalStateException("expected version 0 lms private key");
            }
            final LMSigParameters parametersForType = LMSigParameters.getParametersForType(dataInputStream.readInt());
            final LMOtsParameters parametersForType2 = LMOtsParameters.getParametersForType(dataInputStream.readInt());
            final byte[] b = new byte[16];
            dataInputStream.readFully(b);
            final int int1 = dataInputStream.readInt();
            final int int2 = dataInputStream.readInt();
            final int int3 = dataInputStream.readInt();
            if (int3 < 0) {
                throw new IllegalStateException("secret length less than zero");
            }
            if (int3 > dataInputStream.available()) {
                throw new IOException("secret length exceeded " + dataInputStream.available());
            }
            final byte[] b2 = new byte[int3];
            dataInputStream.readFully(b2);
            return new LMSPrivateKeyParameters(parametersForType, parametersForType2, int1, b, int2, b2);
        }
        else {
            if (obj instanceof byte[]) {
                Object o = null;
                try {
                    o = new DataInputStream(new ByteArrayInputStream((byte[])obj));
                    return getInstance(o);
                }
                finally {
                    if (o != null) {
                        ((InputStream)o).close();
                    }
                }
            }
            if (obj instanceof InputStream) {
                return getInstance(Streams.readAll((InputStream)obj));
            }
            throw new IllegalArgumentException("cannot parse " + obj);
        }
    }
    
    LMOtsPrivateKey getCurrentOTSKey() {
        synchronized (this) {
            if (this.q >= this.maxQ) {
                throw new ExhaustedPrivateKeyException("ots private keys expired");
            }
            return new LMOtsPrivateKey(this.otsParameters, this.I, this.q, this.masterSecret);
        }
    }
    
    public synchronized int getIndex() {
        return this.q;
    }
    
    synchronized void incIndex() {
        ++this.q;
    }
    
    @Override
    public LMSContext generateLMSContext() {
        final int h = this.getSigParameters().getH();
        final int index = this.getIndex();
        final LMOtsPrivateKey nextOtsPrivateKey = this.getNextOtsPrivateKey();
        int i = 0;
        final int n = (1 << h) + index;
        final byte[][] array = new byte[h][];
        while (i < h) {
            array[i] = this.findT(n / (1 << i) ^ 0x1);
            ++i;
        }
        return nextOtsPrivateKey.getSignatureContext(this.getSigParameters(), array);
    }
    
    @Override
    public byte[] generateSignature(final LMSContext lmsContext) {
        try {
            return LMS.generateSign(lmsContext).getEncoded();
        }
        catch (final IOException cause) {
            throw new IllegalStateException("unable to encode signature: " + cause.getMessage(), cause);
        }
    }
    
    LMOtsPrivateKey getNextOtsPrivateKey() {
        synchronized (this) {
            if (this.q >= this.maxQ) {
                throw new ExhaustedPrivateKeyException("ots private key exhausted");
            }
            final LMOtsPrivateKey lmOtsPrivateKey = new LMOtsPrivateKey(this.otsParameters, this.I, this.q, this.masterSecret);
            this.incIndex();
            return lmOtsPrivateKey;
        }
    }
    
    public LMSPrivateKeyParameters extractKeyShard(final int n) {
        synchronized (this) {
            if (n < 0) {
                throw new IllegalArgumentException("usageCount cannot be negative");
            }
            if (n > this.maxQ - this.q) {
                throw new IllegalArgumentException("usageCount exceeds usages remaining");
            }
            final int q = this.q;
            final int q2 = this.q + n;
            this.q = q2;
            return new LMSPrivateKeyParameters(this, q, q2);
        }
    }
    
    public LMSigParameters getSigParameters() {
        return this.parameters;
    }
    
    public LMOtsParameters getOtsParameters() {
        return this.otsParameters;
    }
    
    public byte[] getI() {
        return Arrays.clone(this.I);
    }
    
    public byte[] getMasterSecret() {
        return Arrays.clone(this.masterSecret);
    }
    
    public int getIndexLimit() {
        return this.maxQ;
    }
    
    @Override
    public long getUsagesRemaining() {
        return this.getIndexLimit() - this.getIndex();
    }
    
    public LMSPublicKeyParameters getPublicKey() {
        synchronized (this) {
            if (this.publicKey == null) {
                this.publicKey = new LMSPublicKeyParameters(this.parameters, this.otsParameters, this.findT(LMSPrivateKeyParameters.T1), this.I);
            }
            return this.publicKey;
        }
    }
    
    byte[] findT(final int n) {
        if (n < this.maxCacheR) {
            return this.findT((n < LMSPrivateKeyParameters.internedKeys.length) ? LMSPrivateKeyParameters.internedKeys[n] : new CacheKey(n));
        }
        return this.calcT(n);
    }
    
    private byte[] findT(final CacheKey cacheKey) {
        synchronized (this.tCache) {
            final byte[] array = this.tCache.get(cacheKey);
            if (array != null) {
                return array;
            }
            final byte[] calcT = this.calcT(cacheKey.index);
            this.tCache.put(cacheKey, calcT);
            return calcT;
        }
    }
    
    private byte[] calcT(final int n) {
        final int n2 = 1 << this.getSigParameters().getH();
        if (n >= n2) {
            LmsUtils.byteArray(this.getI(), this.tDigest);
            LmsUtils.u32str(n, this.tDigest);
            LmsUtils.u16str((short)(-32126), this.tDigest);
            LmsUtils.byteArray(LM_OTS.lms_ots_generatePublicKey(this.getOtsParameters(), this.getI(), n - n2, this.getMasterSecret()), this.tDigest);
            final byte[] array = new byte[this.tDigest.getDigestSize()];
            this.tDigest.doFinal(array, 0);
            return array;
        }
        final byte[] t = this.findT(2 * n);
        final byte[] t2 = this.findT(2 * n + 1);
        LmsUtils.byteArray(this.getI(), this.tDigest);
        LmsUtils.u32str(n, this.tDigest);
        LmsUtils.u16str((short)(-31869), this.tDigest);
        LmsUtils.byteArray(t, this.tDigest);
        LmsUtils.byteArray(t2, this.tDigest);
        final byte[] array2 = new byte[this.tDigest.getDigestSize()];
        this.tDigest.doFinal(array2, 0);
        return array2;
    }
    
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || this.getClass() != o.getClass()) {
            return false;
        }
        final LMSPrivateKeyParameters lmsPrivateKeyParameters = (LMSPrivateKeyParameters)o;
        if (this.q != lmsPrivateKeyParameters.q) {
            return false;
        }
        if (this.maxQ != lmsPrivateKeyParameters.maxQ) {
            return false;
        }
        if (!Arrays.areEqual(this.I, lmsPrivateKeyParameters.I)) {
            return false;
        }
        Label_0104: {
            if (this.parameters != null) {
                if (this.parameters.equals(lmsPrivateKeyParameters.parameters)) {
                    break Label_0104;
                }
            }
            else if (lmsPrivateKeyParameters.parameters == null) {
                break Label_0104;
            }
            return false;
        }
        if (this.otsParameters != null) {
            if (this.otsParameters.equals(lmsPrivateKeyParameters.otsParameters)) {
                return Arrays.areEqual(this.masterSecret, lmsPrivateKeyParameters.masterSecret);
            }
        }
        else if (lmsPrivateKeyParameters.otsParameters == null) {
            return Arrays.areEqual(this.masterSecret, lmsPrivateKeyParameters.masterSecret);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        return 31 * (31 * (31 * (31 * (31 * this.q + Arrays.hashCode(this.I)) + ((this.parameters != null) ? this.parameters.hashCode() : 0)) + ((this.otsParameters != null) ? this.otsParameters.hashCode() : 0)) + this.maxQ) + Arrays.hashCode(this.masterSecret);
    }
    
    @Override
    public byte[] getEncoded() throws IOException {
        return Composer.compose().u32str(0).u32str(this.parameters.getType()).u32str(this.otsParameters.getType()).bytes(this.I).u32str(this.q).u32str(this.maxQ).u32str(this.masterSecret.length).bytes(this.masterSecret).build();
    }
    
    static {
        LMSPrivateKeyParameters.T1 = new CacheKey(1);
        (LMSPrivateKeyParameters.internedKeys = new CacheKey[129])[1] = LMSPrivateKeyParameters.T1;
        for (int i = 2; i < LMSPrivateKeyParameters.internedKeys.length; ++i) {
            LMSPrivateKeyParameters.internedKeys[i] = new CacheKey(i);
        }
    }
    
    private static class CacheKey
    {
        private final int index;
        
        CacheKey(final int index) {
            this.index = index;
        }
        
        @Override
        public int hashCode() {
            return this.index;
        }
        
        @Override
        public boolean equals(final Object o) {
            return o instanceof CacheKey && ((CacheKey)o).index == this.index;
        }
    }
}
