ECAlgorithms.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
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 cp = P.getCurve();
11        Q = importPoint(cp, Q);
12
13        // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
14        if (cp instanceof ECCurve.F2m)
15        {
16            ECCurve.F2m f2mCurve = (ECCurve.F2m)cp;
17            if (f2mCurve.isKoblitz())
18            {
19                return P.multiply(a).add(Q.multiply(b));
20            }
21        }
22
23        return implShamirsTrick(P, a, Q, b);
24    }
25
26    /*
27     * "Shamir's Trick", originally due to E. G. Straus
28     * (Addition chains of vectors. American Mathematical Monthly,
29     * 71(7):806-808, Aug./Sept. 1964)
30     * <pre>
31     * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
32     * and scalar l = (lm?, ... , l1, l0).
33     * Output: R = k * P + l * Q.
34     * 1: Z <- P + Q
35     * 2: R <- O
36     * 3: for i from m-1 down to 0 do
37     * 4:        R <- R + R        {point doubling}
38     * 5:        if (ki = 1) and (li = 0) then R <- R + P end if
39     * 6:        if (ki = 0) and (li = 1) then R <- R + Q end if
40     * 7:        if (ki = 1) and (li = 1) then R <- R + Z end if
41     * 8: end for
42     * 9: return R
43     * </pre>
44     */
45    public static ECPoint shamirsTrick(ECPoint P, BigInteger k,
46        ECPoint Q, BigInteger l)
47    {
48        ECCurve cp = P.getCurve();
49        Q = importPoint(cp, Q);
50
51        return implShamirsTrick(P, k, Q, l);
52    }
53
54    public static ECPoint importPoint(ECCurve c, ECPoint p)
55    {
56        ECCurve cp = p.getCurve();
57        if (!c.equals(cp))
58        {
59            throw new IllegalArgumentException("Point must be on the same curve");
60        }
61        return c.importPoint(p);
62    }
63
64    static void implMontgomeryTrick(ECFieldElement[] zs, int off, int len)
65    {
66        /*
67         * Uses the "Montgomery Trick" to invert many field elements, with only a single actual
68         * field inversion. See e.g. the paper:
69         * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick"
70         * by Katsuyuki Okeya, Kouichi Sakurai.
71         */
72
73        ECFieldElement[] c = new ECFieldElement[len];
74        c[0] = zs[off];
75
76        int i = 0;
77        while (++i < len)
78        {
79            c[i] = c[i - 1].multiply(zs[off + i]);
80        }
81
82        ECFieldElement u = c[--i].invert();
83
84        while (i > 0)
85        {
86            int j = off + i--;
87            ECFieldElement tmp = zs[j];
88            zs[j] = c[i].multiply(u);
89            u = u.multiply(tmp);
90        }
91
92        zs[off] = u;
93    }
94
95    static ECPoint implShamirsTrick(ECPoint P, BigInteger k,
96        ECPoint Q, BigInteger l)
97    {
98        ECCurve curve = P.getCurve();
99        ECPoint infinity = curve.getInfinity();
100
101        // TODO conjugate co-Z addition (ZADDC) can return both of these
102        ECPoint PaddQ = P.add(Q);
103        ECPoint PsubQ = P.subtract(Q);
104
105        ECPoint[] points = new ECPoint[]{ Q, PsubQ, P, PaddQ };
106        curve.normalizeAll(points);
107
108        ECPoint[] table = new ECPoint[] {
109            points[3].negate(), points[2].negate(), points[1].negate(),
110            points[0].negate(), infinity, points[0],
111            points[1], points[2], points[3] };
112
113        byte[] jsf = WNafUtil.generateJSF(k, l);
114
115        ECPoint R = infinity;
116
117        int i = jsf.length;
118        while (--i >= 0)
119        {
120            int jsfi = jsf[i];
121            int kDigit = (jsfi >> 4), lDigit = ((jsfi << 28) >> 28);
122
123            int index = 4 + (kDigit * 3) + lDigit;
124            R = R.twicePlus(table[index]);
125        }
126
127        return R;
128    }
129}
130