1package org.bouncycastle.math.ec.custom.sec;
2
3import java.math.BigInteger;
4
5import org.bouncycastle.math.raw.Nat;
6import org.bouncycastle.math.raw.Nat384;
7
8public class SecP384R1Field
9{
10    private static final long M = 0xFFFFFFFFL;
11
12    // 2^384 - 2^128 - 2^96 + 2^32 - 1
13    static final int[] P = new int[]{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF,
14        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
15    static final int[] PExt = new int[]{ 0x00000001, 0xFFFFFFFE, 0x00000000, 0x00000002, 0x00000000, 0xFFFFFFFE,
16        0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000000,
17        0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
18    private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0x00000001,
19        0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFE, 0xFFFFFFFF,
20        0x00000001, 0x00000002 };
21    private static final int P11 = 0xFFFFFFFF;
22    private static final int PExt23 = 0xFFFFFFFF;
23
24    public static void add(int[] x, int[] y, int[] z)
25    {
26        int c = Nat.add(12, x, y, z);
27        if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P)))
28        {
29            addPInvTo(z);
30        }
31    }
32
33    public static void addExt(int[] xx, int[] yy, int[] zz)
34    {
35        int c = Nat.add(24, xx, yy, zz);
36        if (c != 0 || (zz[23] == PExt23 && Nat.gte(24, zz, PExt)))
37        {
38            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
39            {
40                Nat.incAt(24, zz, PExtInv.length);
41            }
42        }
43    }
44
45    public static void addOne(int[] x, int[] z)
46    {
47        int c = Nat.inc(12, x, z);
48        if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P)))
49        {
50            addPInvTo(z);
51        }
52    }
53
54    public static int[] fromBigInteger(BigInteger x)
55    {
56        int[] z = Nat.fromBigInteger(384, x);
57        if (z[11] == P11 && Nat.gte(12, z, P))
58        {
59            Nat.subFrom(12, P, z);
60        }
61        return z;
62    }
63
64    public static void half(int[] x, int[] z)
65    {
66        if ((x[0] & 1) == 0)
67        {
68            Nat.shiftDownBit(12, x, 0, z);
69        }
70        else
71        {
72            int c = Nat.add(12, x, P, z);
73            Nat.shiftDownBit(12, z, c);
74        }
75    }
76
77    public static void multiply(int[] x, int[] y, int[] z)
78    {
79        int[] tt = Nat.create(24);
80        Nat384.mul(x, y, tt);
81        reduce(tt, z);
82    }
83
84    public static void negate(int[] x, int[] z)
85    {
86        if (Nat.isZero(12, x))
87        {
88            Nat.zero(12, z);
89        }
90        else
91        {
92            Nat.sub(12, P, x, z);
93        }
94    }
95
96    public static void reduce(int[] xx, int[] z)
97    {
98        long xx16 = xx[16] & M, xx17 = xx[17] & M, xx18 = xx[18] & M, xx19 = xx[19] & M;
99        long xx20 = xx[20] & M, xx21 = xx[21] & M, xx22 = xx[22] & M, xx23 = xx[23] & M;
100
101        final long n = 1;
102
103        long t0 = (xx[12] & M) + xx20 - n;
104        long t1 = (xx[13] & M) + xx22;
105        long t2 = (xx[14] & M) + xx22 + xx23;
106        long t3 = (xx[15] & M) + xx23;
107        long t4 = xx17 + xx21;
108        long t5 = xx21 - xx23;
109        long t6 = xx22 - xx23;
110
111        long cc = 0;
112        cc += (xx[0] & M) + t0 + t5;
113        z[0] = (int)cc;
114        cc >>= 32;
115        cc += (xx[1] & M) + xx23 - t0 + t1;
116        z[1] = (int)cc;
117        cc >>= 32;
118        cc += (xx[2] & M) - xx21 - t1 + t2;
119        z[2] = (int)cc;
120        cc >>= 32;
121        cc += (xx[3] & M) + t0 - t2 + t3 + t5;
122        z[3] = (int)cc;
123        cc >>= 32;
124        cc += (xx[4] & M) + xx16 + xx21 + t0 + t1 - t3 + t5;
125        z[4] = (int)cc;
126        cc >>= 32;
127        cc += (xx[5] & M) - xx16 + t1 + t2 + t4;
128        z[5] = (int)cc;
129        cc >>= 32;
130        cc += (xx[6] & M) + xx18 - xx17 + t2 + t3;
131        z[6] = (int)cc;
132        cc >>= 32;
133        cc += (xx[7] & M) + xx16 + xx19 - xx18 + t3;
134        z[7] = (int)cc;
135        cc >>= 32;
136        cc += (xx[8] & M) + xx16 + xx17 + xx20 - xx19;
137        z[8] = (int)cc;
138        cc >>= 32;
139        cc += (xx[9] & M) + xx18 - xx20 + t4;
140        z[9] = (int)cc;
141        cc >>= 32;
142        cc += (xx[10] & M) + xx18 + xx19 - t5 + t6;
143        z[10] = (int)cc;
144        cc >>= 32;
145        cc += (xx[11] & M) + xx19 + xx20 - t6;
146        z[11] = (int)cc;
147        cc >>= 32;
148        cc += n;
149
150//        assert cc >= 0;
151
152        reduce32((int)cc, z);
153    }
154
155    public static void reduce32(int x, int[] z)
156    {
157        long cc = 0;
158
159        if (x != 0)
160        {
161            long xx12 = x & M;
162
163            cc += (z[0] & M) + xx12;
164            z[0] = (int)cc;
165            cc >>= 32;
166            cc += (z[1] & M) - xx12;
167            z[1] = (int)cc;
168            cc >>= 32;
169            if (cc != 0)
170            {
171                cc += (z[2] & M);
172                z[2] = (int)cc;
173                cc >>= 32;
174            }
175            cc += (z[3] & M) + xx12;
176            z[3] = (int)cc;
177            cc >>= 32;
178            cc += (z[4] & M) + xx12;
179            z[4] = (int)cc;
180            cc >>= 32;
181
182//            assert cc == 0 || cc == 1;
183        }
184
185        if ((cc != 0 && Nat.incAt(12, z, 5) != 0)
186            || (z[11] == P11 && Nat.gte(12, z, P)))
187        {
188            addPInvTo(z);
189        }
190    }
191
192    public static void square(int[] x, int[] z)
193    {
194        int[] tt = Nat.create(24);
195        Nat384.square(x, tt);
196        reduce(tt, z);
197    }
198
199    public static void squareN(int[] x, int n, int[] z)
200    {
201//        assert n > 0;
202
203        int[] tt = Nat.create(24);
204        Nat384.square(x, tt);
205        reduce(tt, z);
206
207        while (--n > 0)
208        {
209            Nat384.square(z, tt);
210            reduce(tt, z);
211        }
212    }
213
214    public static void subtract(int[] x, int[] y, int[] z)
215    {
216        int c = Nat.sub(12, x, y, z);
217        if (c != 0)
218        {
219            subPInvFrom(z);
220        }
221    }
222
223    public static void subtractExt(int[] xx, int[] yy, int[] zz)
224    {
225        int c = Nat.sub(24, xx, yy, zz);
226        if (c != 0)
227        {
228            if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
229            {
230                Nat.decAt(24, zz, PExtInv.length);
231            }
232        }
233    }
234
235    public static void twice(int[] x, int[] z)
236    {
237        int c = Nat.shiftUpBit(12, x, 0, z);
238        if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P)))
239        {
240            addPInvTo(z);
241        }
242    }
243
244    private static void addPInvTo(int[] z)
245    {
246        long c = (z[0] & M) + 1;
247        z[0] = (int)c;
248        c >>= 32;
249        c += (z[1] & M) - 1;
250        z[1] = (int)c;
251        c >>= 32;
252        if (c != 0)
253        {
254            c += (z[2] & M);
255            z[2] = (int)c;
256            c >>= 32;
257        }
258        c += (z[3] & M) + 1;
259        z[3] = (int)c;
260        c >>= 32;
261        c += (z[4] & M) + 1;
262        z[4] = (int)c;
263        c >>= 32;
264        if (c != 0)
265        {
266            Nat.incAt(12, z, 5);
267        }
268    }
269
270    private static void subPInvFrom(int[] z)
271    {
272        long c = (z[0] & M) - 1;
273        z[0] = (int)c;
274        c >>= 32;
275        c += (z[1] & M) + 1;
276        z[1] = (int)c;
277        c >>= 32;
278        if (c != 0)
279        {
280            c += (z[2] & M);
281            z[2] = (int)c;
282            c >>= 32;
283        }
284        c += (z[3] & M) - 1;
285        z[3] = (int)c;
286        c >>= 32;
287        c += (z[4] & M) - 1;
288        z[4] = (int)c;
289        c >>= 32;
290        if (c != 0)
291        {
292            Nat.decAt(12, z, 5);
293        }
294    }
295}
296