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