001package org.apache.commons.ssl.org.bouncycastle.asn1.x9;
002
003import java.math.BigInteger;
004
005import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector;
006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer;
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1OctetString;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
011import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence;
012import org.bouncycastle.math.ec.ECAlgorithms;
013import org.bouncycastle.math.ec.ECCurve;
014import org.bouncycastle.math.ec.ECPoint;
015import org.bouncycastle.math.field.PolynomialExtensionField;
016
017/**
018 * ASN.1 def for Elliptic-Curve ECParameters structure. See
019 * X9.62, for further details.
020 */
021public class X9ECParameters
022    extends ASN1Object
023    implements X9ObjectIdentifiers
024{
025    private static final BigInteger   ONE = BigInteger.valueOf(1);
026
027    private X9FieldID           fieldID;
028    private ECCurve             curve;
029    private ECPoint             g;
030    private BigInteger          n;
031    private BigInteger          h;
032    private byte[]              seed;
033
034    private X9ECParameters(
035        ASN1Sequence  seq)
036    {
037        if (!(seq.getObjectAt(0) instanceof ASN1Integer)
038           || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE))
039        {
040            throw new IllegalArgumentException("bad version in X9ECParameters");
041        }
042
043        X9Curve     x9c = new X9Curve(
044                        X9FieldID.getInstance(seq.getObjectAt(1)),
045                        ASN1Sequence.getInstance(seq.getObjectAt(2)));
046
047        this.curve = x9c.getCurve();
048        Object p = seq.getObjectAt(3);
049
050        if (p instanceof X9ECPoint)
051        {
052            this.g = ((X9ECPoint)p).getPoint();
053        }
054        else
055        {
056            this.g = new X9ECPoint(curve, (ASN1OctetString)p).getPoint();
057        }
058
059        this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue();
060        this.seed = x9c.getSeed();
061
062        if (seq.size() == 6)
063        {
064            this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue();
065        }
066    }
067
068    public static X9ECParameters getInstance(Object obj)
069    {
070        if (obj instanceof X9ECParameters)
071        {
072            return (X9ECParameters)obj;
073        }
074
075        if (obj != null)
076        {
077            return new X9ECParameters(ASN1Sequence.getInstance(obj));
078        }
079
080        return null;
081    }
082
083    public X9ECParameters(
084        ECCurve     curve,
085        ECPoint     g,
086        BigInteger  n)
087    {
088        this(curve, g, n, ONE, null);
089    }
090
091    public X9ECParameters(
092        ECCurve     curve,
093        ECPoint     g,
094        BigInteger  n,
095        BigInteger  h)
096    {
097        this(curve, g, n, h, null);
098    }
099
100    public X9ECParameters(
101        ECCurve     curve,
102        ECPoint     g,
103        BigInteger  n,
104        BigInteger  h,
105        byte[]      seed)
106    {
107        this.curve = curve;
108        this.g = g.normalize();
109        this.n = n;
110        this.h = h;
111        this.seed = seed;
112
113        if (ECAlgorithms.isFpCurve(curve))
114        {
115            this.fieldID = new X9FieldID(curve.getField().getCharacteristic());
116        }
117        else if (ECAlgorithms.isF2mCurve(curve))
118        {
119            PolynomialExtensionField field = (PolynomialExtensionField)curve.getField();
120            int[] exponents = field.getMinimalPolynomial().getExponentsPresent();
121            if (exponents.length == 3)
122            {
123                this.fieldID = new X9FieldID(exponents[2], exponents[1]);
124            }
125            else if (exponents.length == 5)
126            {
127                this.fieldID = new X9FieldID(exponents[4], exponents[1], exponents[2], exponents[3]);
128            }
129            else
130            {
131                throw new IllegalArgumentException("Only trinomial and pentomial curves are supported");
132            }
133        }
134        else
135        {
136            throw new IllegalArgumentException("'curve' is of an unsupported type");
137        }
138    }
139
140    public ECCurve getCurve()
141    {
142        return curve;
143    }
144
145    public ECPoint getG()
146    {
147        return g;
148    }
149
150    public BigInteger getN()
151    {
152        return n;
153    }
154
155    public BigInteger getH()
156    {
157        if (h == null)
158        {
159            return ONE;        // TODO - this should be calculated, it will cause issues with custom curves.
160        }
161
162        return h;
163    }
164
165    public byte[] getSeed()
166    {
167        return seed;
168    }
169
170    /**
171     * Produce an object suitable for an ASN1OutputStream.
172     * <pre>
173     *  ECParameters ::= SEQUENCE {
174     *      version         INTEGER { ecpVer1(1) } (ecpVer1),
175     *      fieldID         FieldID {{FieldTypes}},
176     *      curve           X9Curve,
177     *      base            X9ECPoint,
178     *      order           INTEGER,
179     *      cofactor        INTEGER OPTIONAL
180     *  }
181     * </pre>
182     */
183    public ASN1Primitive toASN1Primitive()
184    {
185        ASN1EncodableVector v = new ASN1EncodableVector();
186
187        v.add(new ASN1Integer(1));
188        v.add(fieldID);
189        v.add(new X9Curve(curve, seed));
190        v.add(new X9ECPoint(g));
191        v.add(new ASN1Integer(n));
192
193        if (h != null)
194        {
195            v.add(new ASN1Integer(h));
196        }
197
198        return new DERSequence(v);
199    }
200}