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