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

package org.bouncycastle.math.ec.tools;

import java.util.List;
import java.util.Enumeration;
import org.bouncycastle.math.ec.ECFieldElement;
import java.util.Random;
import org.bouncycastle.util.Integers;
import java.util.ArrayList;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.asn1.x9.X9ECParametersHolder;
import java.util.Iterator;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import java.util.Collection;
import java.util.TreeSet;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import java.security.SecureRandom;
import java.math.BigInteger;

public class TraceOptimizer
{
    private static final BigInteger ONE;
    private static final SecureRandom R;
    
    public static void main(final String[] array) {
        final TreeSet set = new TreeSet(enumToList(ECNamedCurveTable.getNames()));
        set.addAll(enumToList(CustomNamedCurves.getNames()));
        for (final String str : set) {
            X9ECParametersHolder x9ECParametersHolder = CustomNamedCurves.getByNameLazy(str);
            if (x9ECParametersHolder == null) {
                x9ECParametersHolder = ECNamedCurveTable.getByNameLazy(str);
            }
            if (x9ECParametersHolder != null) {
                final ECCurve curve = x9ECParametersHolder.getCurve();
                if (!ECAlgorithms.isF2mCurve(curve)) {
                    continue;
                }
                System.out.print(str + ":");
                implPrintNonZeroTraceBits(curve);
            }
        }
    }
    
    public static void printNonZeroTraceBits(final ECCurve ecCurve) {
        if (!ECAlgorithms.isF2mCurve(ecCurve)) {
            throw new IllegalArgumentException("Trace only defined over characteristic-2 fields");
        }
        implPrintNonZeroTraceBits(ecCurve);
    }
    
    public static void implPrintNonZeroTraceBits(final ECCurve ecCurve) {
        final int fieldSize = ecCurve.getFieldSize();
        final ArrayList list = new ArrayList();
        for (int i = 0; i < fieldSize; ++i) {
            if ((i & 0x1) == 0x0 && i) {
                if (list.contains(Integers.valueOf(i >>> 1))) {
                    list.add(Integers.valueOf(i));
                    System.out.print(" " + i);
                }
            }
            else if (calculateTrace(ecCurve.fromBigInteger(TraceOptimizer.ONE.shiftLeft(i))) != 0) {
                list.add(Integers.valueOf(i));
                System.out.print(" " + i);
            }
        }
        System.out.println();
        for (int j = 0; j < 1000; ++j) {
            final BigInteger bigInteger = new BigInteger(fieldSize, TraceOptimizer.R);
            final int calculateTrace = calculateTrace(ecCurve.fromBigInteger(bigInteger));
            int n = 0;
            for (int k = 0; k < list.size(); ++k) {
                if (bigInteger.testBit((int)list.get(k))) {
                    n ^= 0x1;
                }
            }
            if (calculateTrace != n) {
                throw new IllegalStateException("Optimized-trace sanity check failed");
            }
        }
    }
    
    private static int calculateTrace(final ECFieldElement ecFieldElement) {
        final int fieldSize = ecFieldElement.getFieldSize();
        int i = 31 - Integers.numberOfLeadingZeros(fieldSize);
        int n = 1;
        ECFieldElement ecFieldElement2 = ecFieldElement;
        while (i > 0) {
            ecFieldElement2 = ecFieldElement2.squarePow(n).add(ecFieldElement2);
            n = fieldSize >>> --i;
            if (0x0 != (n & 0x1)) {
                ecFieldElement2 = ecFieldElement2.square().add(ecFieldElement);
            }
        }
        if (ecFieldElement2.isZero()) {
            return 0;
        }
        if (ecFieldElement2.isOne()) {
            return 1;
        }
        throw new IllegalStateException("Internal error in trace calculation");
    }
    
    private static List enumToList(final Enumeration enumeration) {
        final ArrayList list = new ArrayList();
        while (enumeration.hasMoreElements()) {
            list.add(enumeration.nextElement());
        }
        return list;
    }
    
    static {
        ONE = BigInteger.valueOf(1L);
        R = new SecureRandom();
    }
}
