18212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrompackage org.bouncycastle.math.ec;
28212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
38212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstromimport java.math.BigInteger;
4d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport java.util.Hashtable;
58212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstromimport java.util.Random;
68212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
7d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.math.ec.endo.ECEndomorphism;
8d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.math.ec.endo.GLVEndomorphism;
9d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.math.field.FiniteField;
10d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.math.field.FiniteFields;
115db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Rootimport org.bouncycastle.util.BigIntegers;
12d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Rootimport org.bouncycastle.util.Integers;
135db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
148212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom/**
158212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom * base class for an elliptic curve
168212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom */
178212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrompublic abstract class ECCurve
188212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom{
195db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public static final int COORD_AFFINE = 0;
205db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public static final int COORD_HOMOGENEOUS = 1;
215db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public static final int COORD_JACOBIAN = 2;
225db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public static final int COORD_JACOBIAN_CHUDNOVSKY = 3;
235db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public static final int COORD_JACOBIAN_MODIFIED = 4;
245db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public static final int COORD_LAMBDA_AFFINE = 5;
255db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public static final int COORD_LAMBDA_PROJECTIVE = 6;
265db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public static final int COORD_SKEWED = 7;
275db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
285db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public static int[] getAllCoordinateSystems()
295db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
305db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
315db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
325db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
335db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
345db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public class Config
355db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
365db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        protected int coord;
37d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        protected ECEndomorphism endomorphism;
385db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        protected ECMultiplier multiplier;
395db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
40d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        Config(int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
415db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
425db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.coord = coord;
43d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.endomorphism = endomorphism;
445db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.multiplier = multiplier;
455db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
465db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
475db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        public Config setCoordinateSystem(int coord)
485db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
495db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.coord = coord;
505db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return this;
515db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
525db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
53d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        public Config setEndomorphism(ECEndomorphism endomorphism)
54d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
55d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.endomorphism = endomorphism;
56d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this;
57d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
58d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
595db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        public Config setMultiplier(ECMultiplier multiplier)
605db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
615db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.multiplier = multiplier;
625db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return this;
635db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
645db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
655db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        public ECCurve create()
665db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
675db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            if (!supportsCoordinateSystem(coord))
685db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
695db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                throw new IllegalStateException("unsupported coordinate system");
705db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
715db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
725db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            ECCurve c = cloneCurve();
735db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            if (c == ECCurve.this)
745db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
755db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                throw new IllegalStateException("implementation returned current curve");
765db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
775db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
785db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            c.coord = coord;
79d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            c.endomorphism = endomorphism;
805db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            c.multiplier = multiplier;
815db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
825db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return c;
835db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
845db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
855db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
86d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    protected FiniteField field;
875db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    protected ECFieldElement a, b;
88d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    protected BigInteger order, cofactor;
89d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
905db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    protected int coord = COORD_AFFINE;
91d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    protected ECEndomorphism endomorphism = null;
925db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    protected ECMultiplier multiplier = null;
938212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
94d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    protected ECCurve(FiniteField field)
95d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
96d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        this.field = field;
97d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
98d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
998212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    public abstract int getFieldSize();
1008212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
1018212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    public abstract ECFieldElement fromBigInteger(BigInteger x);
1028212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
1035db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public Config configure()
1045db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
105d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return new Config(this.coord, this.endomorphism, this.multiplier);
106d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
107d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
108d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint validatePoint(BigInteger x, BigInteger y)
109d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
110d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECPoint p = createPoint(x, y);
111d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!p.isValid())
112d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
113d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            throw new IllegalArgumentException("Invalid point coordinates");
114d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
115d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return p;
116d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
117d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
118d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    /**
119d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @deprecated per-point compression property will be removed, use {@link #validatePoint(BigInteger, BigInteger)}
120d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * and refer {@link ECPoint#getEncoded(boolean)}
121d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     */
122d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECPoint validatePoint(BigInteger x, BigInteger y, boolean withCompression)
123d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
124d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        ECPoint p = createPoint(x, y, withCompression);
125d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (!p.isValid())
126d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
127d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            throw new IllegalArgumentException("Invalid point coordinates");
128d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
129d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return p;
1305db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
1315db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
1325db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public ECPoint createPoint(BigInteger x, BigInteger y)
1335db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
1345db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return createPoint(x, y, false);
1355db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
1365db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
1375db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    /**
1385db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * @deprecated per-point compression property will be removed, use {@link #createPoint(BigInteger, BigInteger)}
1395db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * and refer {@link ECPoint#getEncoded(boolean)}
1405db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     */
1415db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
1425db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
1435db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return createRawPoint(fromBigInteger(x), fromBigInteger(y), withCompression);
1445db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
1455db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
1465db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    protected abstract ECCurve cloneCurve();
1475db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
1485db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression);
1495db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
150d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression);
151d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
1525db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    protected ECMultiplier createDefaultMultiplier()
1535db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
154d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (endomorphism instanceof GLVEndomorphism)
155d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
156d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return new GLVMultiplier(this, (GLVEndomorphism)endomorphism);
157d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
158d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
1595db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return new WNafL2RMultiplier();
1605db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
1615db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
1625db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public boolean supportsCoordinateSystem(int coord)
1635db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
1645db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return coord == COORD_AFFINE;
1655db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
1665db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
167d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public PreCompInfo getPreCompInfo(ECPoint point, String name)
1685db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
169d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        checkPoint(point);
170d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        synchronized (point)
171d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
172d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            Hashtable table = point.preCompTable;
173d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return table == null ? null : (PreCompInfo)table.get(name);
174d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
1755db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
1765db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
1775db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    /**
178d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * Adds <code>PreCompInfo</code> for a point on this curve, under a given name. Used by
1795db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
1805db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * by subsequent multiplication.
1815db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     *
1825db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * @param point
1835db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     *            The <code>ECPoint</code> to store precomputations for.
184d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     * @param name
185d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root     *            A <code>String</code> used to index precomputations of different types.
1865db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * @param preCompInfo
1875db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     *            The values precomputed by the <code>ECMultiplier</code>.
1885db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     */
189d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public void setPreCompInfo(ECPoint point, String name, PreCompInfo preCompInfo)
1905db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
1915db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        checkPoint(point);
192d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        synchronized (point)
193d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
194d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            Hashtable table = point.preCompTable;
195d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (null == table)
196d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            {
197d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                point.preCompTable = table = new Hashtable(4);
198d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
199d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            table.put(name, preCompInfo);
200d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
2015db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
2025db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
2035db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public ECPoint importPoint(ECPoint p)
2045db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
2055db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        if (this == p.getCurve())
2065db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
2075db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return p;
2085db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
2095db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        if (p.isInfinity())
2105db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
2115db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return getInfinity();
2125db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
2135db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
2145db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
2155db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        p = p.normalize();
2165db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
217d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return validatePoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression);
2185db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
2195db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
2205db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    /**
2215db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
2225db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
2235db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * than one point is to be normalized, this method will generally be more efficient than
2245db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * normalizing each point separately.
2255db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     *
2265db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * @param points
2275db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     *            An array of points that will be updated in place with their normalized versions,
2285db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     *            where necessary
2295db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     */
2305db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public void normalizeAll(ECPoint[] points)
2315db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
232028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        normalizeAll(points, 0, points.length, null);
233028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro    }
2345db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
235028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro    /**
236028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
237028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
238028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * than one point is to be normalized, this method will generally be more efficient than
239028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * normalizing each point separately. An (optional) z-scaling factor can be applied; effectively
240028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * each z coordinate is scaled by this value prior to normalization (but only one
241028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * actual multiplication is needed).
242028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     *
243028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * @param points
244028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     *            An array of points that will be updated in place with their normalized versions,
245028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     *            where necessary
246028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * @param off
247028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     *            The start of the range of points to normalize
248028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * @param len
249028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     *            The length of the range of points to normalize
250028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     * @param iso
251028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     *            The (optional) z-scaling factor - can be null
252028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro     */
253028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro    public void normalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso)
254028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro    {
255028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        checkPoints(points, off, len);
256028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro
257028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        switch (this.getCoordinateSystem())
258028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        {
259028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        case ECCurve.COORD_AFFINE:
260028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        case ECCurve.COORD_LAMBDA_AFFINE:
2615db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
262028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro            if (iso != null)
263028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro            {
264028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro                throw new IllegalArgumentException("'iso' not valid for affine coordinates");
265028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro            }
2665db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return;
2675db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
268028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        }
2695db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
2705db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        /*
2715db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root         * Figure out which of the points actually need to be normalized
2725db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root         */
273028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        ECFieldElement[] zs = new ECFieldElement[len];
274028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        int[] indices = new int[len];
2755db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        int count = 0;
276028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        for (int i = 0; i < len; ++i)
2775db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
278028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro            ECPoint p = points[off + i];
279028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro            if (null != p && (iso != null || !p.isNormalized()))
2805db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
2815db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                zs[count] = p.getZCoord(0);
282028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro                indices[count++] = off + i;
2835db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
2845db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
2855db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
2865db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        if (count == 0)
2875db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
2885db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return;
2895db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
2905db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
291028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        ECAlgorithms.montgomeryTrick(zs, 0, count, iso);
2925db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
2935db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        for (int j = 0; j < count; ++j)
2945db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
2955db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            int index = indices[j];
2965db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            points[index] = points[index].normalize(zs[j]);
2975db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
2985db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
2998212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
3008212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    public abstract ECPoint getInfinity();
3018212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
302d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public FiniteField getField()
303d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
304d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return field;
305d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
306d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
3078212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    public ECFieldElement getA()
3088212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    {
3098212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        return a;
3108212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    }
3118212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
3128212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    public ECFieldElement getB()
3138212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    {
3148212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        return b;
3158212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    }
3168212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
317d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public BigInteger getOrder()
318d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
319d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return order;
320d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
321d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
322d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public BigInteger getCofactor()
323d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
324d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return cofactor;
325d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
326d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
3275db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    public int getCoordinateSystem()
3285db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
3295db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return coord;
3305db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
3315db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
332a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1);
333a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
334d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public ECEndomorphism getEndomorphism()
335d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
336d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return endomorphism;
337d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
338d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
339a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    /**
3405db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     * Sets the default <code>ECMultiplier</code>, unless already set.
3415db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root     */
342d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public synchronized ECMultiplier getMultiplier()
3435db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
3445db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        if (this.multiplier == null)
3455db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
3465db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.multiplier = createDefaultMultiplier();
3475db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
3485db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        return this.multiplier;
3495db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
3505db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
3515db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    /**
352a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom     * Decode a point on this curve from its ASN.1 encoding. The different
353a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom     * encodings are taken account of, including point compression for
354a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom     * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
355a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom     * @return The decoded point.
356a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom     */
357a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    public ECPoint decodePoint(byte[] encoded)
358a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    {
359a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        ECPoint p = null;
360a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        int expectedLength = (getFieldSize() + 7) / 8;
361a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
362d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        byte type = encoded[0];
363d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        switch (type)
364a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        {
365a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        case 0x00: // infinity
366a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        {
367a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            if (encoded.length != 1)
368a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            {
369a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom                throw new IllegalArgumentException("Incorrect length for infinity encoding");
370a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            }
371a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
372a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            p = getInfinity();
373a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            break;
374a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        }
375a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        case 0x02: // compressed
376a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        case 0x03: // compressed
377a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        {
378a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            if (encoded.length != (expectedLength + 1))
379a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            {
380a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom                throw new IllegalArgumentException("Incorrect length for compressed encoding");
381a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            }
382a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
383d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            int yTilde = type & 1;
3845db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
385a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
3865db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            p = decompressPoint(yTilde, X);
387d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (!p.satisfiesCofactor())
388d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            {
389d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                throw new IllegalArgumentException("Invalid point");
390d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
391d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
392a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            break;
393a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        }
394a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        case 0x04: // uncompressed
395d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
396d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (encoded.length != (2 * expectedLength + 1))
397d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            {
398d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                throw new IllegalArgumentException("Incorrect length for uncompressed encoding");
399d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
400d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
401d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
402d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength);
403d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
404d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            p = validatePoint(X, Y);
405d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            break;
406d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
407a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        case 0x06: // hybrid
408a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        case 0x07: // hybrid
409a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        {
410a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            if (encoded.length != (2 * expectedLength + 1))
411a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            {
412d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                throw new IllegalArgumentException("Incorrect length for hybrid encoding");
413a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            }
414a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
4155db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength);
4165db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength);
417a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
418d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (Y.testBit(0) != (type == 0x07))
419d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            {
420d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                throw new IllegalArgumentException("Inconsistent Y coordinate in hybrid encoding");
421d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
422d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
423d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            p = validatePoint(X, Y);
424a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            break;
425a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        }
426a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        default:
427d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            throw new IllegalArgumentException("Invalid point encoding 0x" + Integer.toString(type, 16));
428d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
429d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
430d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        if (type != 0x00 && p.isInfinity())
431d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
432d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            throw new IllegalArgumentException("Invalid infinity encoding");
433a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        }
434a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
435a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        return p;
436a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    }
437a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
4385db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    protected void checkPoint(ECPoint point)
439a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    {
4405db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        if (null == point || (this != point.getCurve()))
4415db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
4425db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            throw new IllegalArgumentException("'point' must be non-null and on this curve");
4435db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
4445db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    }
4455db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
4465db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    protected void checkPoints(ECPoint[] points)
4475db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root    {
448028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        checkPoints(points, 0, points.length);
449028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro    }
450028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro
451028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro    protected void checkPoints(ECPoint[] points, int off, int len)
452028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro    {
4535db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        if (points == null)
4545db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
4555db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            throw new IllegalArgumentException("'points' cannot be null");
4565db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
457028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        if (off < 0 || len < 0 || (off > (points.length - len)))
458028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        {
459028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro            throw new IllegalArgumentException("invalid range specified for 'points'");
460028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        }
4615db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
462028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro        for (int i = 0; i < len; ++i)
4635db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
464028ab6e01e3b911024b9b9243e9a0f4ac377c0faSergio Giro            ECPoint point = points[off + i];
4655db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            if (null != point && this != point.getCurve())
4665db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
4675db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                throw new IllegalArgumentException("'points' entries must be null or on this curve");
4685db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
4695db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
470a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom    }
471a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
472d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public boolean equals(ECCurve other)
473d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
474d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return this == other
475d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            || (null != other
476d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                && getField().equals(other.getField())
477d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                && getA().toBigInteger().equals(other.getA().toBigInteger())
478d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                && getB().toBigInteger().equals(other.getB().toBigInteger()));
479d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
480d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
481d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public boolean equals(Object obj)
482d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
483d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return this == obj || (obj instanceof ECCurve && equals((ECCurve)obj));
484d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
485d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
486d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public int hashCode()
487d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
488d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        return getField().hashCode()
489d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            ^ Integers.rotateLeft(getA().toBigInteger().hashCode(), 8)
490d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            ^ Integers.rotateLeft(getB().toBigInteger().hashCode(), 16);
491d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
492d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
493d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public static abstract class AbstractFp extends ECCurve
494d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
495d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        protected AbstractFp(BigInteger q)
496d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
497d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            super(FiniteFields.getPrimeField(q));
498d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
499d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
500d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        protected ECPoint decompressPoint(int yTilde, BigInteger X1)
501d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
502d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            ECFieldElement x = this.fromBigInteger(X1);
503d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            ECFieldElement rhs = x.square().add(a).multiply(x).add(b);
504d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            ECFieldElement y = rhs.sqrt();
505d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
506d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            /*
507d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root             * If y is not a square, then we haven't got a point on the curve
508d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root             */
509d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (y == null)
510d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            {
511d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                throw new IllegalArgumentException("Invalid point compression");
512d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
513d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
514d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (y.testBitZero() != (yTilde == 1))
515d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            {
516d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                // Use the other root
517d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                y = y.negate();
518d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
519d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
520d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this.createRawPoint(x, y, true);
521d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
522d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
523d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
5248212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    /**
5258212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom     * Elliptic curve over Fp
5268212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom     */
527d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public static class Fp extends AbstractFp
5288212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    {
5295db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        private static final int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
5305db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
5315db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        BigInteger q, r;
5328212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        ECPoint.Fp infinity;
5338212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
5348212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public Fp(BigInteger q, BigInteger a, BigInteger b)
5358212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
536d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this(q, a, b, null, null);
537d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
538d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
539d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        public Fp(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
540d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
541d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            super(q);
542d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
5438212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.q = q;
5445db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.r = ECFieldElement.Fp.calculateResidue(q);
5455db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.infinity = new ECPoint.Fp(this, null, null);
5465db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
5478212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.a = fromBigInteger(a);
5488212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.b = fromBigInteger(b);
549d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.order = order;
550d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.cofactor = cofactor;
5515db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.coord = FP_DEFAULT_COORDS;
5525db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
5535db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
5545db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
5555db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
556d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this(q, r, a, b, null, null);
557d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
558d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
559d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
560d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
561d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            super(q);
562d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
5635db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.q = q;
5645db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.r = r;
5658212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.infinity = new ECPoint.Fp(this, null, null);
5665db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
5675db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.a = a;
5685db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.b = b;
569d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.order = order;
570d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.cofactor = cofactor;
5715db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.coord = FP_DEFAULT_COORDS;
5725db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
5735db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
5745db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        protected ECCurve cloneCurve()
5755db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
576d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return new Fp(q, r, a, b, order, cofactor);
5775db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
5785db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
5795db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        public boolean supportsCoordinateSystem(int coord)
5805db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
5815db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            switch (coord)
5825db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
5835db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            case COORD_AFFINE:
5845db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            case COORD_HOMOGENEOUS:
5855db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            case COORD_JACOBIAN:
5865db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            case COORD_JACOBIAN_MODIFIED:
5875db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                return true;
5885db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            default:
5895db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                return false;
5905db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
5918212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
5928212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
5938212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public BigInteger getQ()
5948212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
5958212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return q;
5968212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
5978212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
5988212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public int getFieldSize()
5998212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
6008212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return q.bitLength();
6018212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
6028212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
6038212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public ECFieldElement fromBigInteger(BigInteger x)
6048212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
6055db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return new ECFieldElement.Fp(this.q, this.r, x);
6068212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
6078212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
6085db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
6098212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
6105db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return new ECPoint.Fp(this, x, y, withCompression);
6115db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
6125db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
613d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
614d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
615d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return new ECPoint.Fp(this, x, y, zs, withCompression);
616d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
617d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
6185db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        public ECPoint importPoint(ECPoint p)
6195db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
6205db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            if (this != p.getCurve() && this.getCoordinateSystem() == COORD_JACOBIAN && !p.isInfinity())
6215db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
6225db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                switch (p.getCurve().getCoordinateSystem())
6235db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                {
6245db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                case COORD_JACOBIAN:
6255db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                case COORD_JACOBIAN_CHUDNOVSKY:
6265db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                case COORD_JACOBIAN_MODIFIED:
6275db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                    return new ECPoint.Fp(this,
6285db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                        fromBigInteger(p.x.toBigInteger()),
6295db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                        fromBigInteger(p.y.toBigInteger()),
6305db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                        new ECFieldElement[]{ fromBigInteger(p.zs[0].toBigInteger()) },
6315db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                        p.withCompression);
6325db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                default:
6335db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                    break;
6345db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                }
6355db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
6365db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
6375db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return super.importPoint(p);
6388212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
6398212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
640d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        public ECPoint getInfinity()
6418212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
642d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return infinity;
643d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
644d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    }
645a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
646d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public static abstract class AbstractF2m extends ECCurve
647d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    {
648d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        private static FiniteField buildField(int m, int k1, int k2, int k3)
649d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
650d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (k1 == 0)
6518212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            {
652d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                throw new IllegalArgumentException("k1 must be > 0");
653a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            }
6548212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
655d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (k2 == 0)
656a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom            {
657d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                if (k3 != 0)
658d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                {
659d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    throw new IllegalArgumentException("k3 must be 0 if k2 == 0");
660d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                }
6618212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
662d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                return FiniteFields.getBinaryExtensionField(new int[]{ 0, k1, m });
663d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
6648212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
665d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (k2 <= k1)
6668212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            {
667d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                throw new IllegalArgumentException("k2 must be > k1");
6688212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            }
6698212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
670d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (k3 <= k2)
6718212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            {
672d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                throw new IllegalArgumentException("k3 must be > k2");
6738212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            }
6748212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
675d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return FiniteFields.getBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
6768212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
6778212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
678d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        protected AbstractF2m(int m, int k1, int k2, int k3)
6798212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
680d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            super(buildField(m, k1, k2, k3));
6818212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
6828212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    }
6838212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
6848212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    /**
6858212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom     * Elliptic curves over F2m. The Weierstrass equation is given by
6868212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom     * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
6878212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom     */
688d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root    public static class F2m extends AbstractF2m
6898212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    {
690d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        private static final int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
6915db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
6928212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
6938212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
6948212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
6958212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        private int m;  // can't be final - JDK 1.1
6968212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
6978212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
6988212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
6998212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k</sup> + 1</code> represents the reduction polynomial
7008212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>f(z)</code>.<br>
7018212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
7028212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
7038212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * represents the reduction polynomial <code>f(z)</code>.<br>
7048212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
7058212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        private int k1;  // can't be final - JDK 1.1
7068212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
7078212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
7088212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * TPB: Always set to <code>0</code><br>
7098212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
7108212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
7118212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * represents the reduction polynomial <code>f(z)</code>.<br>
7128212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
7138212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        private int k2;  // can't be final - JDK 1.1
7148212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
7158212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
7168212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * TPB: Always set to <code>0</code><br>
7178212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
7188212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
7198212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * represents the reduction polynomial <code>f(z)</code>.<br>
7208212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
7218212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        private int k3;  // can't be final - JDK 1.1
7228212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
7238212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         /**
7248212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * The point at infinity on this curve.
7258212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
7268212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        private ECPoint.F2m infinity;  // can't be final - JDK 1.1
7278212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
7288212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
7298212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * The parameter <code>&mu;</code> of the elliptic curve if this is
7308212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * a Koblitz curve.
7318212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
7328212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        private byte mu = 0;
7338212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
7348212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
7358212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * The auxiliary values <code>s<sub>0</sub></code> and
7368212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>s<sub>1</sub></code> used for partial modular reduction for
7378212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Koblitz curves.
7388212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
7398212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        private BigInteger[] si = null;
7408212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
7418212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
7428212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Constructor for Trinomial Polynomial Basis (TPB).
7438212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param m  The exponent <code>m</code> of
7448212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
7458212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
7468212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k</sup> + 1</code> represents the reduction
7478212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * polynomial <code>f(z)</code>.
7488212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param a The coefficient <code>a</code> in the Weierstrass equation
7498212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * for non-supersingular elliptic curves over
7508212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
7518212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param b The coefficient <code>b</code> in the Weierstrass equation
7528212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * for non-supersingular elliptic curves over
7538212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
7548212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
7558212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public F2m(
7568212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int m,
7578212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int k,
7588212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            BigInteger a,
7598212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            BigInteger b)
7608212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
7618212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this(m, k, 0, 0, a, b, null, null);
7628212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
7638212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
7648212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
7658212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Constructor for Trinomial Polynomial Basis (TPB).
7668212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param m  The exponent <code>m</code> of
7678212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
7688212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
7698212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k</sup> + 1</code> represents the reduction
7708212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * polynomial <code>f(z)</code>.
7718212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param a The coefficient <code>a</code> in the Weierstrass equation
7728212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * for non-supersingular elliptic curves over
7738212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
7748212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param b The coefficient <code>b</code> in the Weierstrass equation
7758212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * for non-supersingular elliptic curves over
7768212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
777d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root         * @param order The order of the main subgroup of the elliptic curve.
778d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root         * @param cofactor The cofactor of the elliptic curve, i.e.
7798212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
7808212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
7818212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public F2m(
7828212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int m,
7838212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int k,
7848212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            BigInteger a,
7858212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            BigInteger b,
786d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            BigInteger order,
787d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            BigInteger cofactor)
7888212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
789d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this(m, k, 0, 0, a, b, order, cofactor);
7908212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
7918212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
7928212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
7938212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Constructor for Pentanomial Polynomial Basis (PPB).
7948212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param m  The exponent <code>m</code> of
7958212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
7968212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
7978212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
7988212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * represents the reduction polynomial <code>f(z)</code>.
7998212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
8008212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
8018212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * represents the reduction polynomial <code>f(z)</code>.
8028212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
8038212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
8048212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * represents the reduction polynomial <code>f(z)</code>.
8058212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param a The coefficient <code>a</code> in the Weierstrass equation
8068212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * for non-supersingular elliptic curves over
8078212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
8088212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param b The coefficient <code>b</code> in the Weierstrass equation
8098212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * for non-supersingular elliptic curves over
8108212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
8118212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
8128212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public F2m(
8138212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int m,
8148212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int k1,
8158212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int k2,
8168212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int k3,
8178212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            BigInteger a,
8188212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            BigInteger b)
8198212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
8208212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this(m, k1, k2, k3, a, b, null, null);
8218212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
8228212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
8238212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
8248212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Constructor for Pentanomial Polynomial Basis (PPB).
8258212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param m  The exponent <code>m</code> of
8268212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
8278212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
8288212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
8298212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * represents the reduction polynomial <code>f(z)</code>.
8308212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
8318212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
8328212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * represents the reduction polynomial <code>f(z)</code>.
8338212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
8348212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
8358212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * represents the reduction polynomial <code>f(z)</code>.
8368212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param a The coefficient <code>a</code> in the Weierstrass equation
8378212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * for non-supersingular elliptic curves over
8388212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
8398212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param b The coefficient <code>b</code> in the Weierstrass equation
8408212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * for non-supersingular elliptic curves over
8418212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>F<sub>2<sup>m</sup></sub></code>.
842d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root         * @param order The order of the main subgroup of the elliptic curve.
843d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root         * @param cofactor The cofactor of the elliptic curve, i.e.
8448212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
8458212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
8468212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public F2m(
8478212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int m,
8488212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int k1,
8498212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int k2,
8508212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            int k3,
8518212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            BigInteger a,
8528212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            BigInteger b,
853d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            BigInteger order,
854d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            BigInteger cofactor)
8558212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
856d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            super(m, k1, k2, k3);
857d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
8588212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.m = m;
8598212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.k1 = k1;
8608212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.k2 = k2;
8618212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.k3 = k3;
862d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.order = order;
863d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.cofactor = cofactor;
8648212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
8655db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.infinity = new ECPoint.F2m(this, null, null);
8668212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.a = fromBigInteger(a);
8678212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.b = fromBigInteger(b);
8685db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.coord = F2M_DEFAULT_COORDS;
8695db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
8705db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
871d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        protected F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
8725db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
873d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            super(m, k1, k2, k3);
874d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
8755db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.m = m;
8765db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.k1 = k1;
8775db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.k2 = k2;
8785db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.k3 = k3;
879d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.order = order;
880d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            this.cofactor = cofactor;
8815db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
8828212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            this.infinity = new ECPoint.F2m(this, null, null);
8835db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.a = a;
8845db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.b = b;
8855db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            this.coord = F2M_DEFAULT_COORDS;
8865db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
8875db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
8885db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        protected ECCurve cloneCurve()
8895db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
890d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return new F2m(m, k1, k2, k3, a, b, order, cofactor);
8915db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
8925db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
8935db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        public boolean supportsCoordinateSystem(int coord)
8945db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
8955db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            switch (coord)
8965db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
8975db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            case COORD_AFFINE:
8985db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            case COORD_HOMOGENEOUS:
8995db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            case COORD_LAMBDA_PROJECTIVE:
9005db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                return true;
9015db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            default:
9025db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                return false;
9035db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
9045db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
9055db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
9065db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        protected ECMultiplier createDefaultMultiplier()
9075db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
9085db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            if (isKoblitz())
9095db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
9105db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                return new WTauNafMultiplier();
9115db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
9125db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
9135db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return super.createDefaultMultiplier();
9148212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
9158212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
9168212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public int getFieldSize()
9178212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
9188212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return m;
9198212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
9208212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
9218212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public ECFieldElement fromBigInteger(BigInteger x)
9228212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
9238212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);
9248212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
9258212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
9268212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
9278212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
9285db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            ECFieldElement X = fromBigInteger(x), Y = fromBigInteger(y);
9295db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
9305db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            switch (this.getCoordinateSystem())
9315db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
9325db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            case COORD_LAMBDA_AFFINE:
9335db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            case COORD_LAMBDA_PROJECTIVE:
9345db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
935d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                if (X.isZero())
936d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                {
937d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    if (!Y.square().equals(this.getB()))
938d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    {
939d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                        throw new IllegalArgumentException();
940d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    }
941d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                }
942d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                else
9435db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                {
9445db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                    // Y becomes Lambda (X + Y/X) here
9455db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                    Y = Y.divide(X).add(X);
9465db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                }
9475db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                break;
9485db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
9495db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            default:
9505db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            {
9515db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                break;
9525db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
9535db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            }
9545db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
9555db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return createRawPoint(X, Y, withCompression);
9565db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        }
9575db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
9585db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression)
9595db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        {
9605db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            return new ECPoint.F2m(this, x, y, withCompression);
9618212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
9628212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
963d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)
964d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        {
965d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return new ECPoint.F2m(this, x, y, zs, withCompression);
966d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        }
967d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
9688212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public ECPoint getInfinity()
9698212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
9708212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return infinity;
9718212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
9728212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
9738212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
9748212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Returns true if this is a Koblitz curve (ABC curve).
9758212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @return true if this is a Koblitz curve (ABC curve), false otherwise
9768212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
9778212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public boolean isKoblitz()
9788212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
979d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return order != null && cofactor != null && b.isOne() && (a.isZero() || a.isOne());
9808212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
9818212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
9828212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
9838212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Returns the parameter <code>&mu;</code> of the elliptic curve.
9848212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @return <code>&mu;</code> of the elliptic curve.
9858212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @throws IllegalArgumentException if the given ECCurve is not a
9868212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Koblitz curve.
9878212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
9888212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        synchronized byte getMu()
9898212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
9908212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            if (mu == 0)
9918212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            {
9928212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                mu = Tnaf.getMu(this);
9938212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            }
9948212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return mu;
9958212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
9968212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
9978212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
9988212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @return the auxiliary values <code>s<sub>0</sub></code> and
9998212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * <code>s<sub>1</sub></code> used for partial modular reduction for
10008212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Koblitz curves.
10018212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
10028212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        synchronized BigInteger[] getSi()
10038212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
10048212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            if (si == null)
10058212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            {
10068212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                si = Tnaf.getSi(this);
10078212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            }
10088212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return si;
10098212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
10108212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
10118212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
10128212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
10138212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         *
1014a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom         * @param yTilde
10158212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         *            ~yp, an indication bit for the decompression of yp.
1016a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom         * @param X1
1017a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom         *            The field element xp.
10188212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @return the decompressed point.
10198212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
1020a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom        protected ECPoint decompressPoint(int yTilde, BigInteger X1)
10218212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
1022d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            ECFieldElement x = fromBigInteger(X1), y = null;
1023d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (x.isZero())
10248212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            {
1025d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                y = b.sqrt();
10268212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            }
10278212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            else
10288212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            {
1029d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                ECFieldElement beta = x.square().invert().multiply(b).add(a).add(x);
10305db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                ECFieldElement z = solveQuadraticEquation(beta);
1031d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                if (z != null)
10328212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                {
1033d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    if (z.testBitZero() != (yTilde == 1))
1034d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    {
1035d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                        z = z.addOne();
1036d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    }
1037d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
1038d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    switch (this.getCoordinateSystem())
1039d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    {
1040d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    case COORD_LAMBDA_AFFINE:
1041d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    case COORD_LAMBDA_PROJECTIVE:
1042d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    {
1043d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                        y = z.add(x);
1044d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                        break;
1045d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    }
1046d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    default:
1047d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    {
1048d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                        y = z.multiply(x);
1049d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                        break;
1050d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    }
1051d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                    }
10528212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                }
1053d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            }
10545db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
1055d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            if (y == null)
1056d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            {
1057d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root                throw new IllegalArgumentException("Invalid point compression");
10588212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            }
1059a198e1ecc615e26a167d0f2dca9fa7e5fc62de10Brian Carlstrom
1060d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return this.createRawPoint(x, y, true);
10618212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
1062d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root
10638212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
10648212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
10658212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * D.1.6) The other solution is <code>z + 1</code>.
10668212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         *
10678212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @param beta
10685db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root         *            The value to solve the quadratic equation for.
10698212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
10708212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         *         <code>null</code> if no solution exists.
10718212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
10725db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        private ECFieldElement solveQuadraticEquation(ECFieldElement beta)
10738212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
10745db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            if (beta.isZero())
10758212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            {
10765db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                return beta;
10778212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            }
10788212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
10795db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            ECFieldElement zeroElement = fromBigInteger(ECConstants.ZERO);
10805db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root
10818212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            ECFieldElement z = null;
10825db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            ECFieldElement gamma = null;
10838212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
10848212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            Random rand = new Random();
10858212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            do
10868212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            {
10875db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                ECFieldElement t = fromBigInteger(new BigInteger(m, rand));
10888212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                z = zeroElement;
10898212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                ECFieldElement w = beta;
10908212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                for (int i = 1; i <= m - 1; i++)
10918212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                {
10928212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                    ECFieldElement w2 = w.square();
10938212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                    z = z.square().add(w2.multiply(t));
10948212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                    w = w2.add(beta);
10958212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                }
10965db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root                if (!w.isZero())
10978212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                {
10988212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                    return null;
10998212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                }
11008212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom                gamma = z.square().add(z);
11018212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            }
11025db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root            while (gamma.isZero());
11038212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
11048212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return z;
11058212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
11068212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
11078212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public int getM()
11088212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
11098212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return m;
11108212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
11118212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
11128212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        /**
11138212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * Return true if curve uses a Trinomial basis.
11148212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         *
11158212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         * @return true if curve Trinomial, false otherwise.
11168212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom         */
11178212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public boolean isTrinomial()
11188212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
11198212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return k2 == 0 && k3 == 0;
11208212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
11218212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
11228212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public int getK1()
11238212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
11248212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return k1;
11258212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
11268212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
11278212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public int getK2()
11288212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
11298212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return k2;
11308212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
11318212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
11328212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public int getK3()
11338212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
11348212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom            return k3;
11358212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
11368212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
1137d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        /**
1138d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root         * @deprecated use {@link #getOrder()} instead
1139d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root         */
11408212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public BigInteger getN()
11418212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
1142d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return order;
11438212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
11448212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom
1145d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root        /**
1146d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root         * @deprecated use {@link #getCofactor()} instead
1147d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root         */
11488212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        public BigInteger getH()
11498212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        {
1150d001700a15b8bd733ae344c1fc315b97c43c6590Kenny Root            return cofactor;
11518212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom        }
11528212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom    }
11538212855a312dc8ebe081a3e08b1d2d8f8757af02Brian Carlstrom}
1154