/src/serenity/Userland/Libraries/LibCrypto/NumberTheory/ModularFunctions.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/Debug.h> |
8 | | #include <LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h> |
9 | | #include <LibCrypto/NumberTheory/ModularFunctions.h> |
10 | | |
11 | | namespace Crypto::NumberTheory { |
12 | | |
13 | | UnsignedBigInteger Mod(UnsignedBigInteger const& a, UnsignedBigInteger const& b) |
14 | 0 | { |
15 | 0 | UnsignedBigInteger result; |
16 | 0 | result.set_to(a); |
17 | 0 | result.set_to(result.divided_by(b).remainder); |
18 | 0 | return result; |
19 | 0 | } |
20 | | |
21 | | UnsignedBigInteger ModularInverse(UnsignedBigInteger const& a_, UnsignedBigInteger const& b) |
22 | 0 | { |
23 | 0 | if (b == 1) |
24 | 0 | return { 1 }; |
25 | | |
26 | 0 | UnsignedBigInteger temp_1; |
27 | 0 | UnsignedBigInteger temp_minus; |
28 | 0 | UnsignedBigInteger temp_quotient; |
29 | 0 | UnsignedBigInteger temp_d; |
30 | 0 | UnsignedBigInteger temp_u; |
31 | 0 | UnsignedBigInteger temp_v; |
32 | 0 | UnsignedBigInteger temp_x; |
33 | 0 | UnsignedBigInteger result; |
34 | |
|
35 | 0 | UnsignedBigIntegerAlgorithms::modular_inverse_without_allocation(a_, b, temp_1, temp_minus, temp_quotient, temp_d, temp_u, temp_v, temp_x, result); |
36 | 0 | return result; |
37 | 0 | } |
38 | | |
39 | | UnsignedBigInteger ModularPower(UnsignedBigInteger const& b, UnsignedBigInteger const& e, UnsignedBigInteger const& m) |
40 | 0 | { |
41 | 0 | if (m == 1) |
42 | 0 | return 0; |
43 | | |
44 | 0 | if (m.is_odd()) { |
45 | 0 | UnsignedBigInteger temp_z0 { 0 }; |
46 | 0 | UnsignedBigInteger temp_rr { 0 }; |
47 | 0 | UnsignedBigInteger temp_one { 0 }; |
48 | 0 | UnsignedBigInteger temp_z { 0 }; |
49 | 0 | UnsignedBigInteger temp_zz { 0 }; |
50 | 0 | UnsignedBigInteger temp_x { 0 }; |
51 | 0 | UnsignedBigInteger temp_extra { 0 }; |
52 | |
|
53 | 0 | UnsignedBigInteger result; |
54 | 0 | UnsignedBigIntegerAlgorithms::montgomery_modular_power_with_minimal_allocations(b, e, m, temp_z0, temp_rr, temp_one, temp_z, temp_zz, temp_x, temp_extra, result); |
55 | 0 | return result; |
56 | 0 | } |
57 | | |
58 | 0 | UnsignedBigInteger ep { e }; |
59 | 0 | UnsignedBigInteger base { b }; |
60 | |
|
61 | 0 | UnsignedBigInteger result; |
62 | 0 | UnsignedBigInteger temp_1; |
63 | 0 | UnsignedBigInteger temp_2; |
64 | 0 | UnsignedBigInteger temp_3; |
65 | 0 | UnsignedBigInteger temp_multiply; |
66 | 0 | UnsignedBigInteger temp_quotient; |
67 | 0 | UnsignedBigInteger temp_remainder; |
68 | |
|
69 | 0 | UnsignedBigIntegerAlgorithms::destructive_modular_power_without_allocation(ep, base, m, temp_1, temp_2, temp_3, temp_multiply, temp_quotient, temp_remainder, result); |
70 | |
|
71 | 0 | return result; |
72 | 0 | } |
73 | | |
74 | | UnsignedBigInteger GCD(UnsignedBigInteger const& a, UnsignedBigInteger const& b) |
75 | 0 | { |
76 | 0 | UnsignedBigInteger temp_a { a }; |
77 | 0 | UnsignedBigInteger temp_b { b }; |
78 | 0 | UnsignedBigInteger temp_quotient; |
79 | 0 | UnsignedBigInteger temp_remainder; |
80 | 0 | UnsignedBigInteger output; |
81 | |
|
82 | 0 | UnsignedBigIntegerAlgorithms::destructive_GCD_without_allocation(temp_a, temp_b, temp_quotient, temp_remainder, output); |
83 | |
|
84 | 0 | return output; |
85 | 0 | } |
86 | | |
87 | | UnsignedBigInteger LCM(UnsignedBigInteger const& a, UnsignedBigInteger const& b) |
88 | 0 | { |
89 | 0 | UnsignedBigInteger temp_a { a }; |
90 | 0 | UnsignedBigInteger temp_b { b }; |
91 | 0 | UnsignedBigInteger temp_1; |
92 | 0 | UnsignedBigInteger temp_2; |
93 | 0 | UnsignedBigInteger temp_3; |
94 | 0 | UnsignedBigInteger temp_quotient; |
95 | 0 | UnsignedBigInteger temp_remainder; |
96 | 0 | UnsignedBigInteger gcd_output; |
97 | 0 | UnsignedBigInteger output { 0 }; |
98 | |
|
99 | 0 | UnsignedBigIntegerAlgorithms::destructive_GCD_without_allocation(temp_a, temp_b, temp_quotient, temp_remainder, gcd_output); |
100 | 0 | if (gcd_output == 0) { |
101 | 0 | dbgln_if(NT_DEBUG, "GCD is zero"); |
102 | 0 | return output; |
103 | 0 | } |
104 | | |
105 | | // output = (a / gcd_output) * b |
106 | 0 | UnsignedBigIntegerAlgorithms::divide_without_allocation(a, gcd_output, temp_quotient, temp_remainder); |
107 | 0 | UnsignedBigIntegerAlgorithms::multiply_without_allocation(temp_quotient, b, temp_1, temp_2, temp_3, output); |
108 | |
|
109 | 0 | dbgln_if(NT_DEBUG, "quot: {} rem: {} out: {}", temp_quotient, temp_remainder, output); |
110 | |
|
111 | 0 | return output; |
112 | 0 | } |
113 | | |
114 | | static bool MR_primality_test(UnsignedBigInteger n, Vector<UnsignedBigInteger, 256> const& tests) |
115 | 0 | { |
116 | | // Written using Wikipedia: |
117 | | // https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Miller%E2%80%93Rabin_test |
118 | 0 | VERIFY(!(n < 4)); |
119 | 0 | auto predecessor = n.minus({ 1 }); |
120 | 0 | auto d = predecessor; |
121 | 0 | size_t r = 0; |
122 | |
|
123 | 0 | { |
124 | 0 | auto div_result = d.divided_by(2); |
125 | 0 | while (div_result.remainder == 0) { |
126 | 0 | d = div_result.quotient; |
127 | 0 | div_result = d.divided_by(2); |
128 | 0 | ++r; |
129 | 0 | } |
130 | 0 | } |
131 | 0 | if (r == 0) { |
132 | | // n - 1 is odd, so n was even. But there is only one even prime: |
133 | 0 | return n == 2; |
134 | 0 | } |
135 | | |
136 | 0 | for (auto& a : tests) { |
137 | | // Technically: VERIFY(2 <= a && a <= n - 2) |
138 | 0 | VERIFY(a < n); |
139 | 0 | auto x = ModularPower(a, d, n); |
140 | 0 | if (x == 1 || x == predecessor) |
141 | 0 | continue; |
142 | 0 | bool skip_this_witness = false; |
143 | | // r − 1 iterations. |
144 | 0 | for (size_t i = 0; i < r - 1; ++i) { |
145 | 0 | x = ModularPower(x, 2, n); |
146 | 0 | if (x == predecessor) { |
147 | 0 | skip_this_witness = true; |
148 | 0 | break; |
149 | 0 | } |
150 | 0 | } |
151 | 0 | if (skip_this_witness) |
152 | 0 | continue; |
153 | 0 | return false; // "composite" |
154 | 0 | } |
155 | | |
156 | 0 | return true; // "probably prime" |
157 | 0 | } |
158 | | |
159 | | UnsignedBigInteger random_number(UnsignedBigInteger const& min, UnsignedBigInteger const& max_excluded) |
160 | 0 | { |
161 | 0 | VERIFY(min < max_excluded); |
162 | 0 | auto range = max_excluded.minus(min); |
163 | 0 | UnsignedBigInteger base; |
164 | 0 | auto size = range.trimmed_length() * sizeof(u32) + 2; |
165 | | // "+2" is intentional (see below). |
166 | 0 | auto buffer = ByteBuffer::create_uninitialized(size).release_value_but_fixme_should_propagate_errors(); // FIXME: Handle possible OOM situation. |
167 | 0 | auto* buf = buffer.data(); |
168 | |
|
169 | 0 | fill_with_random(buffer); |
170 | 0 | UnsignedBigInteger random { buf, size }; |
171 | | // At this point, `random` is a large number, in the range [0, 256^size). |
172 | | // To get down to the actual range, we could just compute random % range. |
173 | | // This introduces "modulo bias". However, since we added 2 to `size`, |
174 | | // we know that the generated range is at least 65536 times as large as the |
175 | | // required range! This means that the modulo bias is only 0.0015%, if all |
176 | | // inputs are chosen adversarially. Let's hope this is good enough. |
177 | 0 | auto divmod = random.divided_by(range); |
178 | | // The proper way to fix this is to restart if `divmod.quotient` is maximal. |
179 | 0 | return divmod.remainder.plus(min); |
180 | 0 | } |
181 | | |
182 | | bool is_probably_prime(UnsignedBigInteger const& p) |
183 | 0 | { |
184 | | // Is it a small number? |
185 | 0 | if (p < 49) { |
186 | 0 | u32 p_value = p.words()[0]; |
187 | | // Is it a very small prime? |
188 | 0 | if (p_value == 2 || p_value == 3 || p_value == 5 || p_value == 7) |
189 | 0 | return true; |
190 | | // Is it the multiple of a very small prime? |
191 | 0 | if (p_value % 2 == 0 || p_value % 3 == 0 || p_value % 5 == 0 || p_value % 7 == 0) |
192 | 0 | return false; |
193 | | // Then it must be a prime, but not a very small prime, like 37. |
194 | 0 | return true; |
195 | 0 | } |
196 | | |
197 | 0 | Vector<UnsignedBigInteger, 256> tests; |
198 | | // Make some good initial guesses that are guaranteed to find all primes < 2^64. |
199 | 0 | tests.append(UnsignedBigInteger(2)); |
200 | 0 | tests.append(UnsignedBigInteger(3)); |
201 | 0 | tests.append(UnsignedBigInteger(5)); |
202 | 0 | tests.append(UnsignedBigInteger(7)); |
203 | 0 | tests.append(UnsignedBigInteger(11)); |
204 | 0 | tests.append(UnsignedBigInteger(13)); |
205 | 0 | UnsignedBigInteger seventeen { 17 }; |
206 | 0 | for (size_t i = tests.size(); i < 256; ++i) { |
207 | 0 | tests.append(random_number(seventeen, p.minus(2))); |
208 | 0 | } |
209 | | // Miller-Rabin's "error" is 8^-k. In adversarial cases, it's 4^-k. |
210 | | // With 200 random numbers, this would mean an error of about 2^-400. |
211 | | // So we don't need to worry too much about the quality of the random numbers. |
212 | |
|
213 | 0 | return MR_primality_test(p, tests); |
214 | 0 | } |
215 | | |
216 | | UnsignedBigInteger random_big_prime(size_t bits) |
217 | 0 | { |
218 | 0 | VERIFY(bits >= 33); |
219 | 0 | UnsignedBigInteger min = "6074001000"_bigint.shift_left(bits - 33); |
220 | 0 | UnsignedBigInteger max = UnsignedBigInteger { 1 }.shift_left(bits).minus(1); |
221 | 0 | for (;;) { |
222 | 0 | auto p = random_number(min, max); |
223 | 0 | if ((p.words()[0] & 1) == 0) { |
224 | | // An even number is definitely not a large prime. |
225 | 0 | continue; |
226 | 0 | } |
227 | 0 | if (is_probably_prime(p)) |
228 | 0 | return p; |
229 | 0 | } |
230 | 0 | } |
231 | | |
232 | | } |