1package org.bouncycastle.asn1.x9;
2
3import java.math.BigInteger;
4
5import org.bouncycastle.asn1.ASN1EncodableVector;
6import org.bouncycastle.asn1.ASN1Integer;
7import org.bouncycastle.asn1.ASN1Object;
8import org.bouncycastle.asn1.ASN1OctetString;
9import org.bouncycastle.asn1.ASN1Primitive;
10import org.bouncycastle.asn1.ASN1Sequence;
11import org.bouncycastle.asn1.DERSequence;
12import org.bouncycastle.math.ec.ECCurve;
13import org.bouncycastle.math.ec.ECPoint;
14
15/**
16 * ASN.1 def for Elliptic-Curve ECParameters structure. See
17 * X9.62, for further details.
18 */
19public class X9ECParameters
20    extends ASN1Object
21    implements X9ObjectIdentifiers
22{
23    private static final BigInteger   ONE = BigInteger.valueOf(1);
24
25    private X9FieldID           fieldID;
26    private ECCurve             curve;
27    private ECPoint             g;
28    private BigInteger          n;
29    private BigInteger          h;
30    private byte[]              seed;
31
32    private X9ECParameters(
33        ASN1Sequence  seq)
34    {
35        if (!(seq.getObjectAt(0) instanceof ASN1Integer)
36           || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE))
37        {
38            throw new IllegalArgumentException("bad version in X9ECParameters");
39        }
40
41        X9Curve     x9c = new X9Curve(
42                        X9FieldID.getInstance(seq.getObjectAt(1)),
43                        ASN1Sequence.getInstance(seq.getObjectAt(2)));
44
45        this.curve = x9c.getCurve();
46        Object p = seq.getObjectAt(3);
47
48        if (p instanceof X9ECPoint)
49        {
50            this.g = ((X9ECPoint)p).getPoint();
51        }
52        else
53        {
54            this.g = new X9ECPoint(curve, (ASN1OctetString)p).getPoint();
55        }
56
57        this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue();
58        this.seed = x9c.getSeed();
59
60        if (seq.size() == 6)
61        {
62            this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue();
63        }
64    }
65
66    public static X9ECParameters getInstance(Object obj)
67    {
68        if (obj instanceof X9ECParameters)
69        {
70            return (X9ECParameters)obj;
71        }
72
73        if (obj != null)
74        {
75            return new X9ECParameters(ASN1Sequence.getInstance(obj));
76        }
77
78        return null;
79    }
80
81    public X9ECParameters(
82        ECCurve     curve,
83        ECPoint     g,
84        BigInteger  n)
85    {
86        this(curve, g, n, ONE, null);
87    }
88
89    public X9ECParameters(
90        ECCurve     curve,
91        ECPoint     g,
92        BigInteger  n,
93        BigInteger  h)
94    {
95        this(curve, g, n, h, null);
96    }
97
98    public X9ECParameters(
99        ECCurve     curve,
100        ECPoint     g,
101        BigInteger  n,
102        BigInteger  h,
103        byte[]      seed)
104    {
105        this.curve = curve;
106        this.g = g.normalize();
107        this.n = n;
108        this.h = h;
109        this.seed = seed;
110
111        if (curve instanceof ECCurve.Fp)
112        {
113            this.fieldID = new X9FieldID(((ECCurve.Fp)curve).getQ());
114        }
115        else
116        {
117            if (curve instanceof ECCurve.F2m)
118            {
119                ECCurve.F2m curveF2m = (ECCurve.F2m)curve;
120                this.fieldID = new X9FieldID(curveF2m.getM(), curveF2m.getK1(),
121                    curveF2m.getK2(), curveF2m.getK3());
122            }
123        }
124    }
125
126    public ECCurve getCurve()
127    {
128        return curve;
129    }
130
131    public ECPoint getG()
132    {
133        return g;
134    }
135
136    public BigInteger getN()
137    {
138        return n;
139    }
140
141    public BigInteger getH()
142    {
143        if (h == null)
144        {
145            return ONE;        // TODO - this should be calculated, it will cause issues with custom curves.
146        }
147
148        return h;
149    }
150
151    public byte[] getSeed()
152    {
153        return seed;
154    }
155
156    /**
157     * Produce an object suitable for an ASN1OutputStream.
158     * <pre>
159     *  ECParameters ::= SEQUENCE {
160     *      version         INTEGER { ecpVer1(1) } (ecpVer1),
161     *      fieldID         FieldID {{FieldTypes}},
162     *      curve           X9Curve,
163     *      base            X9ECPoint,
164     *      order           INTEGER,
165     *      cofactor        INTEGER OPTIONAL
166     *  }
167     * </pre>
168     */
169    public ASN1Primitive toASN1Primitive()
170    {
171        ASN1EncodableVector v = new ASN1EncodableVector();
172
173        v.add(new ASN1Integer(1));
174        v.add(fieldID);
175        v.add(new X9Curve(curve, seed));
176        v.add(new X9ECPoint(g));
177        v.add(new ASN1Integer(n));
178
179        if (h != null)
180        {
181            v.add(new ASN1Integer(h));
182        }
183
184        return new DERSequence(v);
185    }
186}
187