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

package org.bouncycastle.crypto.params;

import org.bouncycastle.util.Integers;
import org.bouncycastle.math.raw.Nat;
import java.math.BigInteger;

public class DHPublicKeyParameters extends DHKeyParameters
{
    private static final BigInteger ONE;
    private static final BigInteger TWO;
    private BigInteger y;
    
    public DHPublicKeyParameters(final BigInteger bigInteger, final DHParameters dhParameters) {
        super(false, dhParameters);
        this.y = this.validate(bigInteger, dhParameters);
    }
    
    private BigInteger validate(final BigInteger bigInteger, final DHParameters dhParameters) {
        if (bigInteger == null) {
            throw new NullPointerException("y value cannot be null");
        }
        final BigInteger p2 = dhParameters.getP();
        if (bigInteger.compareTo(DHPublicKeyParameters.TWO) < 0 || bigInteger.compareTo(p2.subtract(DHPublicKeyParameters.TWO)) > 0) {
            throw new IllegalArgumentException("invalid DH public key");
        }
        final BigInteger q = dhParameters.getQ();
        if (q == null) {
            return bigInteger;
        }
        if (p2.testBit(0) && p2.bitLength() - 1 == q.bitLength() && p2.shiftRight(1).equals(q)) {
            if (1 == legendre(bigInteger, p2)) {
                return bigInteger;
            }
        }
        else if (DHPublicKeyParameters.ONE.equals(bigInteger.modPow(q, p2))) {
            return bigInteger;
        }
        throw new IllegalArgumentException("Y value does not appear to be in correct group");
    }
    
    public BigInteger getY() {
        return this.y;
    }
    
    @Override
    public int hashCode() {
        return this.y.hashCode() ^ super.hashCode();
    }
    
    @Override
    public boolean equals(final Object o) {
        return o instanceof DHPublicKeyParameters && ((DHPublicKeyParameters)o).getY().equals(this.y) && super.equals(o);
    }
    
    private static int legendre(final BigInteger bigInteger, final BigInteger bigInteger2) {
        final int bitLength = bigInteger2.bitLength();
        int[] fromBigInteger = Nat.fromBigInteger(bitLength, bigInteger);
        int[] fromBigInteger2 = Nat.fromBigInteger(bitLength, bigInteger2);
        int n = 0;
        int length = fromBigInteger2.length;
        while (true) {
            if (fromBigInteger[0] == 0) {
                Nat.shiftDownWord(length, fromBigInteger, 0);
            }
            else {
                final int numberOfTrailingZeros = Integers.numberOfTrailingZeros(fromBigInteger[0]);
                if (numberOfTrailingZeros > 0) {
                    Nat.shiftDownBits(length, fromBigInteger, numberOfTrailingZeros, 0);
                    final int n2 = fromBigInteger2[0];
                    n ^= ((n2 ^ n2 >>> 1) & numberOfTrailingZeros << 1);
                }
                final int compare = Nat.compare(length, fromBigInteger, fromBigInteger2);
                if (compare == 0) {
                    break;
                }
                if (compare < 0) {
                    n ^= (fromBigInteger[0] & fromBigInteger2[0]);
                    final int[] array = fromBigInteger;
                    fromBigInteger = fromBigInteger2;
                    fromBigInteger2 = array;
                }
                while (fromBigInteger[length - 1] == 0) {
                    --length;
                }
                Nat.sub(length, fromBigInteger, fromBigInteger2, fromBigInteger);
            }
        }
        return Nat.isOne(length, fromBigInteger2) ? (1 - (n & 0x2)) : 0;
    }
    
    static {
        ONE = BigInteger.valueOf(1L);
        TWO = BigInteger.valueOf(2L);
    }
}
