ECAlgorithms.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.math.ec;
2
3import java.math.BigInteger;
4
5public class ECAlgorithms
6{
7    public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a,
8        ECPoint Q, BigInteger b)
9    {
10        ECCurve c = P.getCurve();
11        if (!c.equals(Q.getCurve()))
12        {
13            throw new IllegalArgumentException("P and Q must be on same curve");
14        }
15
16        // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
17        if (c instanceof ECCurve.F2m)
18        {
19            ECCurve.F2m f2mCurve = (ECCurve.F2m)c;
20            if (f2mCurve.isKoblitz())
21            {
22                return P.multiply(a).add(Q.multiply(b));
23            }
24        }
25
26        return implShamirsTrick(P, a, Q, b);
27    }
28
29    /*
30     * "Shamir's Trick", originally due to E. G. Straus
31     * (Addition chains of vectors. American Mathematical Monthly,
32     * 71(7):806-808, Aug./Sept. 1964)
33     * <pre>
34     * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
35     * and scalar l = (lm?, ... , l1, l0).
36     * Output: R = k * P + l * Q.
37     * 1: Z <- P + Q
38     * 2: R <- O
39     * 3: for i from m-1 down to 0 do
40     * 4:        R <- R + R        {point doubling}
41     * 5:        if (ki = 1) and (li = 0) then R <- R + P end if
42     * 6:        if (ki = 0) and (li = 1) then R <- R + Q end if
43     * 7:        if (ki = 1) and (li = 1) then R <- R + Z end if
44     * 8: end for
45     * 9: return R
46     * </pre>
47     */
48    public static ECPoint shamirsTrick(ECPoint P, BigInteger k,
49        ECPoint Q, BigInteger l)
50    {
51        if (!P.getCurve().equals(Q.getCurve()))
52        {
53            throw new IllegalArgumentException("P and Q must be on same curve");
54        }
55
56        return implShamirsTrick(P, k, Q, l);
57    }
58
59    private static ECPoint implShamirsTrick(ECPoint P, BigInteger k,
60        ECPoint Q, BigInteger l)
61    {
62        int m = Math.max(k.bitLength(), l.bitLength());
63        ECPoint Z = P.add(Q);
64        ECPoint R = P.getCurve().getInfinity();
65
66        for (int i = m - 1; i >= 0; --i)
67        {
68            R = R.twice();
69
70            if (k.testBit(i))
71            {
72                if (l.testBit(i))
73                {
74                    R = R.add(Z);
75                }
76                else
77                {
78                    R = R.add(P);
79                }
80            }
81            else
82            {
83                if (l.testBit(i))
84                {
85                    R = R.add(Q);
86                }
87            }
88        }
89
90        return R;
91    }
92}
93