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.ASN1ObjectIdentifier;
9import org.bouncycastle.asn1.ASN1OctetString;
10import org.bouncycastle.asn1.ASN1Primitive;
11import org.bouncycastle.asn1.ASN1Sequence;
12import org.bouncycastle.asn1.DERBitString;
13import org.bouncycastle.asn1.DERSequence;
14import org.bouncycastle.math.ec.ECCurve;
15
16/**
17 * ASN.1 def for Elliptic-Curve Curve structure. See
18 * X9.62, for further details.
19 */
20public class X9Curve
21    extends ASN1Object
22    implements X9ObjectIdentifiers
23{
24    private ECCurve     curve;
25    private byte[]      seed;
26    private ASN1ObjectIdentifier fieldIdentifier = null;
27
28    public X9Curve(
29        ECCurve     curve)
30    {
31        this.curve = curve;
32        this.seed = null;
33        setFieldIdentifier();
34    }
35
36    public X9Curve(
37        ECCurve     curve,
38        byte[]      seed)
39    {
40        this.curve = curve;
41        this.seed = seed;
42        setFieldIdentifier();
43    }
44
45    public X9Curve(
46        X9FieldID     fieldID,
47        ASN1Sequence  seq)
48    {
49        fieldIdentifier = fieldID.getIdentifier();
50        if (fieldIdentifier.equals(prime_field))
51        {
52            BigInteger      p = ((ASN1Integer)fieldID.getParameters()).getValue();
53            X9FieldElement  x9A = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(0));
54            X9FieldElement  x9B = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(1));
55            curve = new ECCurve.Fp(p, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());
56        }
57        else if (fieldIdentifier.equals(characteristic_two_field))
58        {
59            // Characteristic two field
60            ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters());
61            int m = ((ASN1Integer)parameters.getObjectAt(0)).getValue().
62                intValue();
63            ASN1ObjectIdentifier representation
64                = (ASN1ObjectIdentifier)parameters.getObjectAt(1);
65
66            int k1 = 0;
67            int k2 = 0;
68            int k3 = 0;
69
70            if (representation.equals(tpBasis))
71            {
72                // Trinomial basis representation
73                k1 = ASN1Integer.getInstance(parameters.getObjectAt(2)).getValue().intValue();
74            }
75            else if (representation.equals(ppBasis))
76            {
77                // Pentanomial basis representation
78                ASN1Sequence pentanomial = ASN1Sequence.getInstance(parameters.getObjectAt(2));
79                k1 = ASN1Integer.getInstance(pentanomial.getObjectAt(0)).getValue().intValue();
80                k2 = ASN1Integer.getInstance(pentanomial.getObjectAt(1)).getValue().intValue();
81                k3 = ASN1Integer.getInstance(pentanomial.getObjectAt(2)).getValue().intValue();
82            }
83            else
84            {
85                throw new IllegalArgumentException("This type of EC basis is not implemented");
86            }
87            X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(0));
88            X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(1));
89            // TODO Is it possible to get the order (n) and cofactor(h) too?
90            curve = new ECCurve.F2m(m, k1, k2, k3, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());
91        }
92        else
93        {
94            throw new IllegalArgumentException("This type of ECCurve is not implemented");
95        }
96
97        if (seq.size() == 3)
98        {
99            seed = ((DERBitString)seq.getObjectAt(2)).getBytes();
100        }
101    }
102
103    private void setFieldIdentifier()
104    {
105        if (curve instanceof ECCurve.Fp)
106        {
107            fieldIdentifier = prime_field;
108        }
109        else if (curve instanceof ECCurve.F2m)
110        {
111            fieldIdentifier = characteristic_two_field;
112        }
113        else
114        {
115            throw new IllegalArgumentException("This type of ECCurve is not implemented");
116        }
117    }
118
119    public ECCurve  getCurve()
120    {
121        return curve;
122    }
123
124    public byte[]   getSeed()
125    {
126        return seed;
127    }
128
129    /**
130     * Produce an object suitable for an ASN1OutputStream.
131     * <pre>
132     *  Curve ::= SEQUENCE {
133     *      a               FieldElement,
134     *      b               FieldElement,
135     *      seed            BIT STRING      OPTIONAL
136     *  }
137     * </pre>
138     */
139    public ASN1Primitive toASN1Primitive()
140    {
141        ASN1EncodableVector v = new ASN1EncodableVector();
142
143        if (fieldIdentifier.equals(prime_field))
144        {
145            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
146            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
147        }
148        else if (fieldIdentifier.equals(characteristic_two_field))
149        {
150            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
151            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
152        }
153
154        if (seed != null)
155        {
156            v.add(new DERBitString(seed));
157        }
158
159        return new DERSequence(v);
160    }
161}
162