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

package org.bouncycastle.crypto.kems;

import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters;
import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.math.ec.ECPoint;
import java.math.BigInteger;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.crypto.EncapsulatedSecretExtractor;

public class SAKKEKEMExtractor implements EncapsulatedSecretExtractor
{
    private final ECCurve curve;
    private final BigInteger p;
    private final BigInteger q;
    private final ECPoint P;
    private final ECPoint Z_S;
    private final ECPoint K_bs;
    private final int n;
    private final BigInteger identifier;
    private final Digest digest;
    
    public SAKKEKEMExtractor(final SAKKEPrivateKeyParameters sakkePrivateKeyParameters) {
        final SAKKEPublicKeyParameters publicParams = sakkePrivateKeyParameters.getPublicParams();
        this.curve = publicParams.getCurve();
        this.q = publicParams.getQ();
        this.P = publicParams.getPoint();
        this.p = publicParams.getPrime();
        this.Z_S = publicParams.getZ();
        this.identifier = publicParams.getIdentifier();
        this.K_bs = this.P.multiply(this.identifier.add(sakkePrivateKeyParameters.getMasterSecret()).modInverse(this.q)).normalize();
        this.n = publicParams.getN();
        this.digest = publicParams.getDigest();
    }
    
    @Override
    public byte[] extractSecret(final byte[] array) {
        final ECPoint decodePoint = this.curve.decodePoint(Arrays.copyOfRange(array, 0, 257));
        final BigInteger mod = BigIntegers.fromUnsignedByteArray(array, 257, 16).xor(SAKKEKEMSGenerator.hashToIntegerRange(computePairing(decodePoint, this.K_bs, this.p, this.q).toByteArray(), BigInteger.ONE.shiftLeft(this.n), this.digest)).mod(this.p);
        final BigInteger identifier = this.identifier;
        final BigInteger hashToIntegerRange = SAKKEKEMSGenerator.hashToIntegerRange(Arrays.concatenate(mod.toByteArray(), identifier.toByteArray()), this.q, this.digest);
        final BigInteger order = this.curve.getOrder();
        ECPoint ecPoint;
        if (order == null) {
            ecPoint = this.P.multiply(identifier).add(this.Z_S).multiply(hashToIntegerRange);
        }
        else {
            ecPoint = ECAlgorithms.sumOfTwoMultiplies(this.P, identifier.multiply(hashToIntegerRange).mod(order), this.Z_S, hashToIntegerRange);
        }
        if (!ecPoint.subtract(decodePoint).isInfinity()) {
            throw new IllegalStateException("Validation of R_bS failed");
        }
        return BigIntegers.asUnsignedByteArray(this.n / 8, mod);
    }
    
    @Override
    public int getEncapsulationLength() {
        return 273;
    }
    
    static BigInteger computePairing(final ECPoint ecPoint, final ECPoint ecPoint2, final BigInteger bigInteger, final BigInteger bigInteger2) {
        BigInteger[] array = { BigInteger.ONE, BigInteger.ZERO };
        ECPoint ecPoint3 = ecPoint;
        final BigInteger subtract = bigInteger2.subtract(BigInteger.ONE);
        final int bitLength = subtract.bitLength();
        final BigInteger bigInteger3 = ecPoint2.getAffineXCoord().toBigInteger();
        final BigInteger bigInteger4 = ecPoint2.getAffineYCoord().toBigInteger();
        final BigInteger bigInteger5 = ecPoint.getAffineXCoord().toBigInteger();
        final BigInteger bigInteger6 = ecPoint.getAffineYCoord().toBigInteger();
        final BigInteger value = BigInteger.valueOf(3L);
        for (int i = bitLength - 2; i >= 0; --i) {
            final BigInteger bigInteger7 = ecPoint3.getAffineXCoord().toBigInteger();
            final BigInteger bigInteger8 = ecPoint3.getAffineYCoord().toBigInteger();
            final BigInteger mod = bigInteger7.multiply(bigInteger7).mod(bigInteger).subtract(BigInteger.ONE).multiply(value).multiply(BigIntegers.modOddInverse(bigInteger, bigInteger8.shiftLeft(1))).mod(bigInteger);
            final BigInteger[] fp2PointSquare = fp2PointSquare(array[0], array[1], bigInteger);
            array = fp2Multiply(fp2PointSquare[0], fp2PointSquare[1], mod.multiply(bigInteger3.add(bigInteger7)).subtract(bigInteger8).mod(bigInteger), bigInteger4, bigInteger);
            ecPoint3 = ecPoint3.twice().normalize();
            if (subtract.testBit(i)) {
                final BigInteger bigInteger9 = ecPoint3.getAffineXCoord().toBigInteger();
                final BigInteger bigInteger10 = ecPoint3.getAffineYCoord().toBigInteger();
                array = fp2Multiply(array[0], array[1], bigInteger10.subtract(bigInteger6).multiply(BigIntegers.modOddInverse(bigInteger, bigInteger9.subtract(bigInteger5))).mod(bigInteger).multiply(bigInteger3.add(bigInteger9)).subtract(bigInteger10).mod(bigInteger), bigInteger4, bigInteger);
                if (i > 0) {
                    ecPoint3 = ecPoint3.add(ecPoint).normalize();
                }
            }
        }
        final BigInteger[] fp2PointSquare2 = fp2PointSquare(array[0], array[1], bigInteger);
        final BigInteger[] fp2PointSquare3 = fp2PointSquare(fp2PointSquare2[0], fp2PointSquare2[1], bigInteger);
        return fp2PointSquare3[1].multiply(BigIntegers.modOddInverse(bigInteger, fp2PointSquare3[0])).mod(bigInteger);
    }
    
    static BigInteger[] fp2Multiply(final BigInteger bigInteger, final BigInteger bigInteger2, final BigInteger bigInteger3, final BigInteger bigInteger4, final BigInteger bigInteger5) {
        return new BigInteger[] { bigInteger.multiply(bigInteger3).subtract(bigInteger2.multiply(bigInteger4)).mod(bigInteger5), bigInteger.multiply(bigInteger4).add(bigInteger2.multiply(bigInteger3)).mod(bigInteger5) };
    }
    
    static BigInteger[] fp2PointSquare(final BigInteger bigInteger, final BigInteger val, final BigInteger bigInteger2) {
        return new BigInteger[] { bigInteger.add(val).multiply(bigInteger.subtract(val)).mod(bigInteger2), bigInteger.multiply(val).shiftLeft(1).mod(bigInteger2) };
    }
}
