1package org.bouncycastle.math.ec.custom.sec;
2
3import java.math.BigInteger;
4
5import org.bouncycastle.math.raw.Nat;
6import org.bouncycastle.math.raw.Nat256;
7
8public class SecP256K1Field
9{
10    // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
11    static final int[] P = new int[]{ 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
12        0xFFFFFFFF, 0xFFFFFFFF };
13    static final int[] PExt = new int[]{ 0x000E90A1, 0x000007A2, 0x00000001, 0x00000000, 0x00000000,
14        0x00000000, 0x00000000, 0x00000000, 0xFFFFF85E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
15        0xFFFFFFFF, 0xFFFFFFFF };
16    private static final int[] PExtInv = new int[]{ 0xFFF16F5F, 0xFFFFF85D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
17        0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000007A1, 0x00000002 };
18    private static final int P7 = 0xFFFFFFFF;
19    private static final int PExt15 = 0xFFFFFFFF;
20    private static final int PInv33 = 0x3D1;
21
22    public static void add(int[] x, int[] y, int[] z)
23    {
24        int c = Nat256.add(x, y, z);
25        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
26        {
27            Nat.add33To(8, PInv33, z);
28        }
29    }
30
31    public static void addExt(int[] xx, int[] yy, int[] zz)
32    {
33        int c = Nat.add(16, xx, yy, zz);
34        if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt)))
35        {
36            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
37            {
38                Nat.incAt(16, zz, PExtInv.length);
39            }
40        }
41    }
42
43    public static void addOne(int[] x, int[] z)
44    {
45        int c = Nat.inc(8, x, z);
46        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
47        {
48            Nat.add33To(8, PInv33, z);
49        }
50    }
51
52    public static int[] fromBigInteger(BigInteger x)
53    {
54        int[] z = Nat256.fromBigInteger(x);
55        if (z[7] == P7 && Nat256.gte(z, P))
56        {
57            Nat256.subFrom(P, z);
58        }
59        return z;
60    }
61
62    public static void half(int[] x, int[] z)
63    {
64        if ((x[0] & 1) == 0)
65        {
66            Nat.shiftDownBit(8, x, 0, z);
67        }
68        else
69        {
70            int c = Nat256.add(x, P, z);
71            Nat.shiftDownBit(8, z, c);
72        }
73    }
74
75    public static void multiply(int[] x, int[] y, int[] z)
76    {
77        int[] tt = Nat256.createExt();
78        Nat256.mul(x, y, tt);
79        reduce(tt, z);
80    }
81
82    public static void multiplyAddToExt(int[] x, int[] y, int[] zz)
83    {
84        int c = Nat256.mulAddTo(x, y, zz);
85        if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt)))
86        {
87            if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0)
88            {
89                Nat.incAt(16, zz, PExtInv.length);
90            }
91        }
92    }
93
94    public static void negate(int[] x, int[] z)
95    {
96        if (Nat256.isZero(x))
97        {
98            Nat256.zero(z);
99        }
100        else
101        {
102            Nat256.sub(P, x, z);
103        }
104    }
105
106    public static void reduce(int[] xx, int[] z)
107    {
108        long cc = Nat256.mul33Add(PInv33, xx, 8, xx, 0, z, 0);
109        int c = Nat256.mul33DWordAdd(PInv33, cc, z, 0);
110
111        // assert c == 0L || c == 1L;
112
113        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
114        {
115            Nat.add33To(8, PInv33, z);
116        }
117    }
118
119    public static void reduce32(int x, int[] z)
120    {
121        if ((x != 0 && Nat256.mul33WordAdd(PInv33, x, z, 0) != 0)
122            || (z[7] == P7 && Nat256.gte(z, P)))
123        {
124            Nat.add33To(8, PInv33, z);
125        }
126    }
127
128    public static void square(int[] x, int[] z)
129    {
130        int[] tt = Nat256.createExt();
131        Nat256.square(x, tt);
132        reduce(tt, z);
133    }
134
135    public static void squareN(int[] x, int n, int[] z)
136    {
137//        assert n > 0;
138
139        int[] tt = Nat256.createExt();
140        Nat256.square(x, tt);
141        reduce(tt, z);
142
143        while (--n > 0)
144        {
145            Nat256.square(z, tt);
146            reduce(tt, z);
147        }
148    }
149
150    public static void subtract(int[] x, int[] y, int[] z)
151    {
152        int c = Nat256.sub(x, y, z);
153        if (c != 0)
154        {
155            Nat.sub33From(8, PInv33, z);
156        }
157    }
158
159    public static void subtractExt(int[] xx, int[] yy, int[] zz)
160    {
161        int c = Nat.sub(16, xx, yy, zz);
162        if (c != 0)
163        {
164            if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0)
165            {
166                Nat.decAt(16, zz, PExtInv.length);
167            }
168        }
169    }
170
171    public static void twice(int[] x, int[] z)
172    {
173        int c = Nat.shiftUpBit(8, x, 0, z);
174        if (c != 0 || (z[7] == P7 && Nat256.gte(z, P)))
175        {
176            Nat.add33To(8, PInv33, z);
177        }
178    }
179}
180