/src/botan/src/fuzzer/invert.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * (C) 2015,2016,2020 Jack Lloyd |
3 | | * |
4 | | * Botan is released under the Simplified BSD License (see license.txt) |
5 | | */ |
6 | | #include "fuzzers.h" |
7 | | |
8 | | #include <botan/numthry.h> |
9 | | |
10 | | namespace { |
11 | | |
12 | 1.22k | Botan::BigInt ref_inverse_mod(const Botan::BigInt& n, const Botan::BigInt& mod) { |
13 | 1.22k | if(n == 0 || mod < 2) { |
14 | 8 | return 0; |
15 | 8 | } |
16 | 1.21k | if(n.is_even() && mod.is_even()) { |
17 | 6 | return 0; |
18 | 6 | } |
19 | 1.21k | Botan::BigInt u = mod, v = n; |
20 | 1.21k | Botan::BigInt A = 1, B = 0, C = 0, D = 1; |
21 | | |
22 | 453k | while(u.is_nonzero()) { |
23 | 452k | const size_t u_zero_bits = Botan::low_zero_bits(u); |
24 | 452k | u >>= u_zero_bits; |
25 | 1.12M | for(size_t i = 0; i != u_zero_bits; ++i) { |
26 | 675k | if(A.is_odd() || B.is_odd()) { |
27 | 333k | A += n; |
28 | 333k | B -= mod; |
29 | 333k | } |
30 | 675k | A >>= 1; |
31 | 675k | B >>= 1; |
32 | 675k | } |
33 | | |
34 | 452k | const size_t v_zero_bits = Botan::low_zero_bits(v); |
35 | 452k | v >>= v_zero_bits; |
36 | 1.08M | for(size_t i = 0; i != v_zero_bits; ++i) { |
37 | 632k | if(C.is_odd() || D.is_odd()) { |
38 | 291k | C += n; |
39 | 291k | D -= mod; |
40 | 291k | } |
41 | 632k | C >>= 1; |
42 | 632k | D >>= 1; |
43 | 632k | } |
44 | | |
45 | 452k | if(u >= v) { |
46 | 139k | u -= v; |
47 | 139k | A -= C; |
48 | 139k | B -= D; |
49 | 312k | } else { |
50 | 312k | v -= u; |
51 | 312k | C -= A; |
52 | 312k | D -= B; |
53 | 312k | } |
54 | 452k | } |
55 | | |
56 | 1.21k | if(v != 1) { |
57 | 132 | return 0; // no modular inverse |
58 | 132 | } |
59 | | |
60 | 2.14k | while(D.is_negative()) { |
61 | 1.06k | D += mod; |
62 | 1.06k | } |
63 | 2.55k | while(D >= mod) { |
64 | 1.47k | D -= mod; |
65 | 1.47k | } |
66 | | |
67 | 1.08k | return D; |
68 | 1.21k | } |
69 | | |
70 | | } // namespace |
71 | | |
72 | 1.23k | void fuzz(std::span<const uint8_t> in) { |
73 | 1.23k | static const size_t max_bits = 4096; |
74 | | |
75 | 1.23k | if(in.size() > 2 * max_bits / 8) { |
76 | 9 | return; |
77 | 9 | } |
78 | | |
79 | 1.22k | const Botan::BigInt x = Botan::BigInt::from_bytes(in.subspan(0, in.size() / 2)); |
80 | 1.22k | Botan::BigInt mod = Botan::BigInt::from_bytes(in.subspan(in.size() / 2, in.size() - in.size() / 2)); |
81 | | |
82 | 1.22k | if(mod < 2) { |
83 | 1 | return; |
84 | 1 | } |
85 | | |
86 | 1.22k | const Botan::BigInt lib = Botan::inverse_mod(x, mod); |
87 | 1.22k | const Botan::BigInt ref = ref_inverse_mod(x, mod); |
88 | | |
89 | 1.22k | if(ref != lib) { |
90 | 0 | FUZZER_WRITE_AND_CRASH("X = " << x.to_hex_string() << "\n" |
91 | 0 | << "Mod = " << mod.to_hex_string() << "\n" |
92 | 0 | << "GCD(X,Mod) = " << gcd(x, mod).to_hex_string() << "\n" |
93 | 0 | << "RefInv(X,Mod) = " << ref.to_hex_string() << "\n" |
94 | 0 | << "LibInv(X,Mod) = " << lib.to_hex_string() << "\n" |
95 | 0 | << "RefCheck = " << ((x * ref) % mod).to_hex_string() << "\n" |
96 | 0 | << "LibCheck = " << ((x * lib) % mod).to_hex_string() << "\n"); |
97 | 0 | } |
98 | 1.22k | } |