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.ASN1ObjectIdentifier;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1OctetString;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
012import org.apache.commons.ssl.org.bouncycastle.asn1.DERBitString;
013import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence;
014import org.bouncycastle.math.ec.ECAlgorithms;
015import org.bouncycastle.math.ec.ECCurve;
016
017/**
018 * ASN.1 def for Elliptic-Curve Curve structure. See
019 * X9.62, for further details.
020 */
021public class X9Curve
022    extends ASN1Object
023    implements X9ObjectIdentifiers
024{
025    private ECCurve     curve;
026    private byte[]      seed;
027    private ASN1ObjectIdentifier fieldIdentifier = null;
028
029    public X9Curve(
030        ECCurve     curve)
031    {
032        this.curve = curve;
033        this.seed = null;
034        setFieldIdentifier();
035    }
036
037    public X9Curve(
038        ECCurve     curve,
039        byte[]      seed)
040    {
041        this.curve = curve;
042        this.seed = seed;
043        setFieldIdentifier();
044    }
045
046    public X9Curve(
047        X9FieldID     fieldID,
048        ASN1Sequence  seq)
049    {
050        // TODO Is it possible to get the order(n) and cofactor(h) too?
051
052        fieldIdentifier = fieldID.getIdentifier();
053        if (fieldIdentifier.equals(prime_field))
054        {
055            BigInteger      p = ((ASN1Integer)fieldID.getParameters()).getValue();
056            X9FieldElement  x9A = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(0));
057            X9FieldElement  x9B = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(1));
058            curve = new ECCurve.Fp(p, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());
059        }
060        else if (fieldIdentifier.equals(characteristic_two_field)) 
061        {
062            // Characteristic two field
063            ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters());
064            int m = ((ASN1Integer)parameters.getObjectAt(0)).getValue().
065                intValue();
066            ASN1ObjectIdentifier representation
067                = (ASN1ObjectIdentifier)parameters.getObjectAt(1);
068
069            int k1 = 0;
070            int k2 = 0;
071            int k3 = 0;
072
073            if (representation.equals(tpBasis)) 
074            {
075                // Trinomial basis representation
076                k1 = ASN1Integer.getInstance(parameters.getObjectAt(2)).getValue().intValue();
077            }
078            else if (representation.equals(ppBasis))
079            {
080                // Pentanomial basis representation
081                ASN1Sequence pentanomial = ASN1Sequence.getInstance(parameters.getObjectAt(2));
082                k1 = ASN1Integer.getInstance(pentanomial.getObjectAt(0)).getValue().intValue();
083                k2 = ASN1Integer.getInstance(pentanomial.getObjectAt(1)).getValue().intValue();
084                k3 = ASN1Integer.getInstance(pentanomial.getObjectAt(2)).getValue().intValue();
085            }
086            else
087            {
088                throw new IllegalArgumentException("This type of EC basis is not implemented");
089            }
090            X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(0));
091            X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(1));
092            curve = new ECCurve.F2m(m, k1, k2, k3, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());
093        }
094        else
095        {
096            throw new IllegalArgumentException("This type of ECCurve is not implemented");
097        }
098
099        if (seq.size() == 3)
100        {
101            seed = ((DERBitString)seq.getObjectAt(2)).getBytes();
102        }
103    }
104
105    private void setFieldIdentifier()
106    {
107        if (ECAlgorithms.isFpCurve(curve))
108        {
109            fieldIdentifier = prime_field;
110        }
111        else if (ECAlgorithms.isF2mCurve(curve))
112        {
113            fieldIdentifier = characteristic_two_field;
114        }
115        else
116        {
117            throw new IllegalArgumentException("This type of ECCurve is not implemented");
118        }
119    }
120
121    public ECCurve  getCurve()
122    {
123        return curve;
124    }
125
126    public byte[]   getSeed()
127    {
128        return seed;
129    }
130
131    /**
132     * Produce an object suitable for an ASN1OutputStream.
133     * <pre>
134     *  Curve ::= SEQUENCE {
135     *      a               FieldElement,
136     *      b               FieldElement,
137     *      seed            BIT STRING      OPTIONAL
138     *  }
139     * </pre>
140     */
141    public ASN1Primitive toASN1Primitive()
142    {
143        ASN1EncodableVector v = new ASN1EncodableVector();
144
145        if (fieldIdentifier.equals(prime_field)) 
146        { 
147            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
148            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
149        } 
150        else if (fieldIdentifier.equals(characteristic_two_field)) 
151        {
152            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
153            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
154        }
155
156        if (seed != null)
157        {
158            v.add(new DERBitString(seed));
159        }
160
161        return new DERSequence(v);
162    }
163}