Home | History | Annotate | Download | only in ec
      1 package org.bouncycastle.math.ec;
      2 
      3 import java.math.BigInteger;
      4 
      5 import org.bouncycastle.asn1.x9.X9IntegerConverter;
      6 
      7 /**
      8  * base class for points on elliptic curves.
      9  */
     10 public abstract class ECPoint
     11 {
     12     ECCurve        curve;
     13     ECFieldElement x;
     14     ECFieldElement y;
     15 
     16     protected boolean withCompression;
     17 
     18     protected ECMultiplier multiplier = null;
     19 
     20     protected PreCompInfo preCompInfo = null;
     21 
     22     private static X9IntegerConverter converter = new X9IntegerConverter();
     23 
     24     protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
     25     {
     26         this.curve = curve;
     27         this.x = x;
     28         this.y = y;
     29     }
     30 
     31     public ECCurve getCurve()
     32     {
     33         return curve;
     34     }
     35 
     36     public ECFieldElement getX()
     37     {
     38         return x;
     39     }
     40 
     41     public ECFieldElement getY()
     42     {
     43         return y;
     44     }
     45 
     46     public boolean isInfinity()
     47     {
     48         return x == null && y == null;
     49     }
     50 
     51     public boolean isCompressed()
     52     {
     53         return withCompression;
     54     }
     55 
     56     public boolean equals(
     57         Object  other)
     58     {
     59         if (other == this)
     60         {
     61             return true;
     62         }
     63 
     64         if (!(other instanceof ECPoint))
     65         {
     66             return false;
     67         }
     68 
     69         ECPoint o = (ECPoint)other;
     70 
     71         if (this.isInfinity())
     72         {
     73             return o.isInfinity();
     74         }
     75 
     76         return x.equals(o.x) && y.equals(o.y);
     77     }
     78 
     79     public int hashCode()
     80     {
     81         if (this.isInfinity())
     82         {
     83             return 0;
     84         }
     85 
     86         return x.hashCode() ^ y.hashCode();
     87     }
     88 
     89 //    /**
     90 //     * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.
     91 //     * @param multiplier The <code>ECMultiplier</code> to be used to multiply
     92 //     * this <code>ECPoint</code>.
     93 //     */
     94 //    public void setECMultiplier(ECMultiplier multiplier)
     95 //    {
     96 //        this.multiplier = multiplier;
     97 //    }
     98 
     99     /**
    100      * Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s
    101      * to save the precomputation for this <code>ECPoint</code> to store the
    102      * precomputation result for use by subsequent multiplication.
    103      * @param preCompInfo The values precomputed by the
    104      * <code>ECMultiplier</code>.
    105      */
    106     void setPreCompInfo(PreCompInfo preCompInfo)
    107     {
    108         this.preCompInfo = preCompInfo;
    109     }
    110 
    111     public abstract byte[] getEncoded();
    112 
    113     public abstract ECPoint add(ECPoint b);
    114     public abstract ECPoint subtract(ECPoint b);
    115     public abstract ECPoint negate();
    116     public abstract ECPoint twice();
    117 
    118     /**
    119      * Sets the default <code>ECMultiplier</code>, unless already set.
    120      */
    121     synchronized void assertECMultiplier()
    122     {
    123         if (this.multiplier == null)
    124         {
    125             this.multiplier = new FpNafMultiplier();
    126         }
    127     }
    128 
    129     /**
    130      * Multiplies this <code>ECPoint</code> by the given number.
    131      * @param k The multiplicator.
    132      * @return <code>k * this</code>.
    133      */
    134     public ECPoint multiply(BigInteger k)
    135     {
    136         if (k.signum() < 0)
    137         {
    138             throw new IllegalArgumentException("The multiplicator cannot be negative");
    139         }
    140 
    141         if (this.isInfinity())
    142         {
    143             return this;
    144         }
    145 
    146         if (k.signum() == 0)
    147         {
    148             return this.curve.getInfinity();
    149         }
    150 
    151         assertECMultiplier();
    152         return this.multiplier.multiply(this, k, preCompInfo);
    153     }
    154 
    155     /**
    156      * Elliptic curve points over Fp
    157      */
    158     public static class Fp extends ECPoint
    159     {
    160 
    161         /**
    162          * Create a point which encodes with point compression.
    163          *
    164          * @param curve the curve to use
    165          * @param x affine x co-ordinate
    166          * @param y affine y co-ordinate
    167          */
    168         public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y)
    169         {
    170             this(curve, x, y, false);
    171         }
    172 
    173         /**
    174          * Create a point that encodes with or without point compresion.
    175          *
    176          * @param curve the curve to use
    177          * @param x affine x co-ordinate
    178          * @param y affine y co-ordinate
    179          * @param withCompression if true encode with point compression
    180          */
    181         public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
    182         {
    183             super(curve, x, y);
    184 
    185             if ((x != null && y == null) || (x == null && y != null))
    186             {
    187                 throw new IllegalArgumentException("Exactly one of the field elements is null");
    188             }
    189 
    190             this.withCompression = withCompression;
    191         }
    192 
    193         /**
    194          * return the field element encoded with point compression. (S 4.3.6)
    195          */
    196         public byte[] getEncoded()
    197         {
    198             if (this.isInfinity())
    199             {
    200                 return new byte[1];
    201             }
    202 
    203             int qLength = converter.getByteLength(x);
    204 
    205             if (withCompression)
    206             {
    207                 byte    PC;
    208 
    209                 if (this.getY().toBigInteger().testBit(0))
    210                 {
    211                     PC = 0x03;
    212                 }
    213                 else
    214                 {
    215                     PC = 0x02;
    216                 }
    217 
    218                 byte[]  X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
    219                 byte[]  PO = new byte[X.length + 1];
    220 
    221                 PO[0] = PC;
    222                 System.arraycopy(X, 0, PO, 1, X.length);
    223 
    224                 return PO;
    225             }
    226             else
    227             {
    228                 byte[]  X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
    229                 byte[]  Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);
    230                 byte[]  PO = new byte[X.length + Y.length + 1];
    231 
    232                 PO[0] = 0x04;
    233                 System.arraycopy(X, 0, PO, 1, X.length);
    234                 System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
    235 
    236                 return PO;
    237             }
    238         }
    239 
    240         // B.3 pg 62
    241         public ECPoint add(ECPoint b)
    242         {
    243             if (this.isInfinity())
    244             {
    245                 return b;
    246             }
    247 
    248             if (b.isInfinity())
    249             {
    250                 return this;
    251             }
    252 
    253             // Check if b = this or b = -this
    254             if (this.x.equals(b.x))
    255             {
    256                 if (this.y.equals(b.y))
    257                 {
    258                     // this = b, i.e. this must be doubled
    259                     return this.twice();
    260                 }
    261 
    262                 // this = -b, i.e. the result is the point at infinity
    263                 return this.curve.getInfinity();
    264             }
    265 
    266             ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));
    267 
    268             ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);
    269             ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
    270 
    271             return new ECPoint.Fp(curve, x3, y3);
    272         }
    273 
    274         // B.3 pg 62
    275         public ECPoint twice()
    276         {
    277             if (this.isInfinity())
    278             {
    279                 // Twice identity element (point at infinity) is identity
    280                 return this;
    281             }
    282 
    283             if (this.y.toBigInteger().signum() == 0)
    284             {
    285                 // if y1 == 0, then (x1, y1) == (x1, -y1)
    286                 // and hence this = -this and thus 2(x1, y1) == infinity
    287                 return this.curve.getInfinity();
    288             }
    289 
    290             ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
    291             ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
    292             ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO));
    293 
    294             ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));
    295             ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
    296 
    297             return new ECPoint.Fp(curve, x3, y3, this.withCompression);
    298         }
    299 
    300         // D.3.2 pg 102 (see Note:)
    301         public ECPoint subtract(ECPoint b)
    302         {
    303             if (b.isInfinity())
    304             {
    305                 return this;
    306             }
    307 
    308             // Add -b
    309             return add(b.negate());
    310         }
    311 
    312         public ECPoint negate()
    313         {
    314             return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
    315         }
    316 
    317         /**
    318          * Sets the default <code>ECMultiplier</code>, unless already set.
    319          */
    320         synchronized void assertECMultiplier()
    321         {
    322             if (this.multiplier == null)
    323             {
    324                 this.multiplier = new WNafMultiplier();
    325             }
    326         }
    327     }
    328 
    329     /**
    330      * Elliptic curve points over F2m
    331      */
    332     public static class F2m extends ECPoint
    333     {
    334         /**
    335          * @param curve base curve
    336          * @param x x point
    337          * @param y y point
    338          */
    339         public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)
    340         {
    341             this(curve, x, y, false);
    342         }
    343 
    344         /**
    345          * @param curve base curve
    346          * @param x x point
    347          * @param y y point
    348          * @param withCompression true if encode with point compression.
    349          */
    350         public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
    351         {
    352             super(curve, x, y);
    353 
    354             if ((x != null && y == null) || (x == null && y != null))
    355             {
    356                 throw new IllegalArgumentException("Exactly one of the field elements is null");
    357             }
    358 
    359             if (x != null)
    360             {
    361                 // Check if x and y are elements of the same field
    362                 ECFieldElement.F2m.checkFieldElements(this.x, this.y);
    363 
    364                 // Check if x and a are elements of the same field
    365                 if (curve != null)
    366                 {
    367                     ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
    368                 }
    369             }
    370 
    371             this.withCompression = withCompression;
    372         }
    373 
    374         /* (non-Javadoc)
    375          * @see org.bouncycastle.math.ec.ECPoint#getEncoded()
    376          */
    377         public byte[] getEncoded()
    378         {
    379             if (this.isInfinity())
    380             {
    381                 return new byte[1];
    382             }
    383 
    384             int byteCount = converter.getByteLength(this.x);
    385             byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
    386             byte[] PO;
    387 
    388             if (withCompression)
    389             {
    390                 // See X9.62 4.3.6 and 4.2.2
    391                 PO = new byte[byteCount + 1];
    392 
    393                 PO[0] = 0x02;
    394                 // X9.62 4.2.2 and 4.3.6:
    395                 // if x = 0 then ypTilde := 0, else ypTilde is the rightmost
    396                 // bit of y * x^(-1)
    397                 // if ypTilde = 0, then PC := 02, else PC := 03
    398                 // Note: PC === PO[0]
    399                 if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))
    400                 {
    401                     if (this.getY().multiply(this.getX().invert())
    402                             .toBigInteger().testBit(0))
    403                     {
    404                         // ypTilde = 1, hence PC = 03
    405                         PO[0] = 0x03;
    406                     }
    407                 }
    408 
    409                 System.arraycopy(X, 0, PO, 1, byteCount);
    410             }
    411             else
    412             {
    413                 byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);
    414 
    415                 PO = new byte[byteCount + byteCount + 1];
    416 
    417                 PO[0] = 0x04;
    418                 System.arraycopy(X, 0, PO, 1, byteCount);
    419                 System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);
    420             }
    421 
    422             return PO;
    423         }
    424 
    425         /**
    426          * Check, if two <code>ECPoint</code>s can be added or subtracted.
    427          * @param a The first <code>ECPoint</code> to check.
    428          * @param b The second <code>ECPoint</code> to check.
    429          * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
    430          * cannot be added.
    431          */
    432         private static void checkPoints(ECPoint a, ECPoint b)
    433         {
    434             // Check, if points are on the same curve
    435             if (!(a.curve.equals(b.curve)))
    436             {
    437                 throw new IllegalArgumentException("Only points on the same "
    438                         + "curve can be added or subtracted");
    439             }
    440 
    441 //            ECFieldElement.F2m.checkFieldElements(a.x, b.x);
    442         }
    443 
    444         /* (non-Javadoc)
    445          * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
    446          */
    447         public ECPoint add(ECPoint b)
    448         {
    449             checkPoints(this, b);
    450             return addSimple((ECPoint.F2m)b);
    451         }
    452 
    453         /**
    454          * Adds another <code>ECPoints.F2m</code> to <code>this</code> without
    455          * checking if both points are on the same curve. Used by multiplication
    456          * algorithms, because there all points are a multiple of the same point
    457          * and hence the checks can be omitted.
    458          * @param b The other <code>ECPoints.F2m</code> to add to
    459          * <code>this</code>.
    460          * @return <code>this + b</code>
    461          */
    462         public ECPoint.F2m addSimple(ECPoint.F2m b)
    463         {
    464             ECPoint.F2m other = b;
    465             if (this.isInfinity())
    466             {
    467                 return other;
    468             }
    469 
    470             if (other.isInfinity())
    471             {
    472                 return this;
    473             }
    474 
    475             ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();
    476             ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();
    477 
    478             // Check if other = this or other = -this
    479             if (this.x.equals(x2))
    480             {
    481                 if (this.y.equals(y2))
    482                 {
    483                     // this = other, i.e. this must be doubled
    484                     return (ECPoint.F2m)this.twice();
    485                 }
    486 
    487                 // this = -other, i.e. the result is the point at infinity
    488                 return (ECPoint.F2m)this.curve.getInfinity();
    489             }
    490 
    491             ECFieldElement.F2m lambda
    492                 = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));
    493 
    494             ECFieldElement.F2m x3
    495                 = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());
    496 
    497             ECFieldElement.F2m y3
    498                 = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);
    499 
    500             return new ECPoint.F2m(curve, x3, y3, withCompression);
    501         }
    502 
    503         /* (non-Javadoc)
    504          * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
    505          */
    506         public ECPoint subtract(ECPoint b)
    507         {
    508             checkPoints(this, b);
    509             return subtractSimple((ECPoint.F2m)b);
    510         }
    511 
    512         /**
    513          * Subtracts another <code>ECPoints.F2m</code> from <code>this</code>
    514          * without checking if both points are on the same curve. Used by
    515          * multiplication algorithms, because there all points are a multiple
    516          * of the same point and hence the checks can be omitted.
    517          * @param b The other <code>ECPoints.F2m</code> to subtract from
    518          * <code>this</code>.
    519          * @return <code>this - b</code>
    520          */
    521         public ECPoint.F2m subtractSimple(ECPoint.F2m b)
    522         {
    523             if (b.isInfinity())
    524             {
    525                 return this;
    526             }
    527 
    528             // Add -b
    529             return addSimple((ECPoint.F2m)b.negate());
    530         }
    531 
    532         /* (non-Javadoc)
    533          * @see org.bouncycastle.math.ec.ECPoint#twice()
    534          */
    535         public ECPoint twice()
    536         {
    537             if (this.isInfinity())
    538             {
    539                 // Twice identity element (point at infinity) is identity
    540                 return this;
    541             }
    542 
    543             if (this.x.toBigInteger().signum() == 0)
    544             {
    545                 // if x1 == 0, then (x1, y1) == (x1, x1 + y1)
    546                 // and hence this = -this and thus 2(x1, y1) == infinity
    547                 return this.curve.getInfinity();
    548             }
    549 
    550             ECFieldElement.F2m lambda
    551                 = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));
    552 
    553             ECFieldElement.F2m x3
    554                 = (ECFieldElement.F2m)lambda.square().add(lambda).
    555                     add(this.curve.getA());
    556 
    557             ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);
    558             ECFieldElement.F2m y3
    559                 = (ECFieldElement.F2m)this.x.square().add(
    560                     x3.multiply(lambda.add(ONE)));
    561 
    562             return new ECPoint.F2m(this.curve, x3, y3, withCompression);
    563         }
    564 
    565         public ECPoint negate()
    566         {
    567             return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
    568         }
    569 
    570         /**
    571          * Sets the appropriate <code>ECMultiplier</code>, unless already set.
    572          */
    573         synchronized void assertECMultiplier()
    574         {
    575             if (this.multiplier == null)
    576             {
    577                 if (((ECCurve.F2m)this.curve).isKoblitz())
    578                 {
    579                     this.multiplier = new WTauNafMultiplier();
    580                 }
    581                 else
    582                 {
    583                     this.multiplier = new WNafMultiplier();
    584                 }
    585             }
    586         }
    587     }
    588 }
    589