/src/botan/src/fuzzer/invert.cpp
Line | Count | Source |
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.90k | Botan::BigInt ref_inverse_mod(const Botan::BigInt& n, const Botan::BigInt& mod) { |
13 | 1.90k | if(n == 0 || mod < 2) { |
14 | 14 | return 0; |
15 | 14 | } |
16 | 1.89k | if(n.is_even() && mod.is_even()) { |
17 | 7 | return 0; |
18 | 7 | } |
19 | 1.88k | Botan::BigInt u = mod; |
20 | 1.88k | Botan::BigInt v = n; |
21 | 1.88k | Botan::BigInt A = 1; |
22 | 1.88k | Botan::BigInt B = 0; |
23 | 1.88k | Botan::BigInt C = 0; |
24 | 1.88k | Botan::BigInt D = 1; |
25 | | |
26 | 522k | while(!u.is_zero()) { |
27 | 520k | const size_t u_zero_bits = Botan::low_zero_bits(u); |
28 | 520k | u >>= u_zero_bits; |
29 | 1.32M | for(size_t i = 0; i != u_zero_bits; ++i) { |
30 | 802k | if(A.is_odd() || B.is_odd()) { |
31 | 430k | A += n; |
32 | 430k | B -= mod; |
33 | 430k | } |
34 | 802k | A >>= 1; |
35 | 802k | B >>= 1; |
36 | 802k | } |
37 | | |
38 | 520k | const size_t v_zero_bits = Botan::low_zero_bits(v); |
39 | 520k | v >>= v_zero_bits; |
40 | 1.20M | for(size_t i = 0; i != v_zero_bits; ++i) { |
41 | 686k | if(C.is_odd() || D.is_odd()) { |
42 | 324k | C += n; |
43 | 324k | D -= mod; |
44 | 324k | } |
45 | 686k | C >>= 1; |
46 | 686k | D >>= 1; |
47 | 686k | } |
48 | | |
49 | 520k | if(u >= v) { |
50 | 176k | u -= v; |
51 | 176k | A -= C; |
52 | 176k | B -= D; |
53 | 344k | } else { |
54 | 344k | v -= u; |
55 | 344k | C -= A; |
56 | 344k | D -= B; |
57 | 344k | } |
58 | 520k | } |
59 | | |
60 | 1.88k | if(v != 1) { |
61 | 388 | return 0; // no modular inverse |
62 | 388 | } |
63 | | |
64 | 2.74k | while(D.signum() < 0) { |
65 | 1.25k | D += mod; |
66 | 1.25k | } |
67 | 3.65k | while(D >= mod) { |
68 | 2.16k | D -= mod; |
69 | 2.16k | } |
70 | | |
71 | 1.49k | return D; |
72 | 1.88k | } |
73 | | |
74 | | } // namespace |
75 | | |
76 | 1.92k | void fuzz(std::span<const uint8_t> in) { |
77 | 1.92k | static const size_t max_bits = 4096; |
78 | | |
79 | 1.92k | if(in.size() > 2 * max_bits / 8) { |
80 | 17 | return; |
81 | 17 | } |
82 | | |
83 | 1.90k | const Botan::BigInt x = Botan::BigInt::from_bytes(in.subspan(0, in.size() / 2)); |
84 | 1.90k | const Botan::BigInt mod = Botan::BigInt::from_bytes(in.subspan(in.size() / 2, in.size() - in.size() / 2)); |
85 | | |
86 | 1.90k | if(mod < 2) { |
87 | 4 | return; |
88 | 4 | } |
89 | | |
90 | 1.90k | const Botan::BigInt lib = Botan::inverse_mod(x, mod); |
91 | 1.90k | const Botan::BigInt ref = ref_inverse_mod(x, mod); |
92 | | |
93 | 1.90k | if(ref != lib) { |
94 | 0 | FUZZER_WRITE_AND_CRASH("X = " << x.to_hex_string() << "\n" |
95 | 0 | << "Mod = " << mod.to_hex_string() << "\n" |
96 | 0 | << "GCD(X,Mod) = " << gcd(x, mod).to_hex_string() << "\n" |
97 | 0 | << "RefInv(X,Mod) = " << ref.to_hex_string() << "\n" |
98 | 0 | << "LibInv(X,Mod) = " << lib.to_hex_string() << "\n" |
99 | 0 | << "RefCheck = " << ((x * ref) % mod).to_hex_string() << "\n" |
100 | 0 | << "LibCheck = " << ((x * lib) % mod).to_hex_string() << "\n"); |
101 | 0 | } |
102 | 1.90k | } |