Created
April 15, 2021 23:54
-
-
Save guidovranken/072be361a0aaa2b7b70dc81d5e876168 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <fuzzing/datasource/datasource.hpp> | |
#include <stdexcept> | |
#include <optional> | |
#include <string> | |
#include <iostream> | |
extern "C" { | |
#include <wolfssl/options.h> | |
#include <wolfssl/wolfcrypt/integer.h> | |
} | |
#define CHECK_EQ(expr, res) if ( (expr) != (res) ) { goto end; } | |
#if defined(DEBUG) | |
#define DEBUG_MSG(x) std::cout << x << std::endl; | |
#else | |
#define DEBUG_MSG(...) | |
#endif | |
class Bignum { | |
private: | |
mp_int* mp = nullptr; | |
fuzzing::datasource::Datasource& ds; | |
void init(void); | |
void deinit(void); | |
public: | |
Bignum(fuzzing::datasource::Datasource& ds, std::optional<std::string> s = std::nullopt); | |
~Bignum(); | |
mp_int* GetPtr(); | |
void Set(void); | |
void Set(const std::string& s); | |
std::string ToString(void) const; | |
bool IsZero(void); | |
}; | |
void Bignum::init(void) { | |
if ( mp ) abort(); | |
mp = (mp_int*)malloc(sizeof(mp_int)); | |
if ( mp_init(mp) != MP_OKAY ) { | |
abort(); | |
} | |
} | |
void Bignum::deinit(void) { | |
if ( mp ) { | |
/* noret */ mp_clear(mp); | |
free(mp); | |
mp = nullptr; | |
} | |
} | |
Bignum::Bignum(fuzzing::datasource::Datasource& ds, std::optional<std::string> s) : | |
ds(ds) { | |
init(); | |
if ( s == std::nullopt ) { | |
Set(); | |
} else { | |
Set(*s); | |
} | |
} | |
Bignum::~Bignum() { | |
deinit(); | |
} | |
mp_int* Bignum::GetPtr() { | |
return mp; | |
} | |
void Bignum::Set(void) { | |
std::vector<uint8_t> val; | |
try { | |
val = ds.GetData(0); | |
} catch ( ... ) { | |
deinit(); | |
throw std::logic_error(""); | |
} | |
#if 0 | |
if ( val.size() != 2 ) { | |
deinit(); | |
throw std::logic_error(""); | |
} | |
#endif | |
//size_t size = val.size() > 2 ? 2 : val.size(); | |
if ( mp_read_unsigned_bin(mp, val.data(), val.size()) != 0 ) { | |
//if ( mp_read_unsigned_bin(mp, val.data(), size) != 0 ) { | |
deinit(); | |
throw std::logic_error(""); | |
} | |
} | |
void Bignum::Set(const std::string& s) { | |
if ( mp_read_radix(mp, s.c_str(), 10) != MP_OKAY ) { | |
deinit(); | |
throw std::logic_error(""); | |
} | |
} | |
std::string Bignum::ToString(void) const { | |
int size; | |
if ( mp_radix_size(mp, 10, &size) != MP_OKAY ) { | |
abort(); | |
} | |
char* str = (char*)malloc(size); | |
if ( mp_toradix(mp, str, 10) != MP_OKAY ) { | |
abort(); | |
} | |
std::string ret = std::string(str); | |
free(str); | |
return ret; | |
} | |
bool Bignum::IsZero(void) { | |
return mp_iszero(mp) ? true : false; | |
} | |
std::ostream& operator<<(std::ostream& os, const Bignum& bn) { | |
os << bn.ToString(); | |
return os; | |
} | |
std::optional<std::string> Compute(fuzzing::datasource::Datasource& ds, size_t* numIter, std::optional<std::string> s = std::nullopt, const size_t depth = 0) { | |
if ( depth == 10 ) { | |
return std::nullopt; | |
} | |
try { | |
Bignum A(ds, s), B(ds), C(ds), D(ds); | |
//printf("%s\n", B.ToString().c_str()); | |
if ( B.ToString() == "1000" ) abort(); | |
bool True = true; | |
while ( ds.Get<bool>() ) { | |
#if 0 | |
if ( mp_count_bits(A.GetPtr()) > 16 ) return std::nullopt; | |
if ( mp_count_bits(B.GetPtr()) > 16 ) return std::nullopt; | |
if ( mp_count_bits(C.GetPtr()) > 16 ) return std::nullopt; | |
if ( mp_count_bits(D.GetPtr()) > 16 ) return std::nullopt; | |
#endif | |
if ( *numIter > 10 ) { | |
return std::nullopt; | |
} | |
(*numIter)++; | |
const auto which = ds.Get<uint8_t>(); | |
//if ( which != 0 && which != 3 && which != 4 && which != 18 ) return std::nullopt; | |
//switch ( ds.Get<uint8_t>() ) { | |
//printf("which is: %u\n", which); | |
switch ( which ) { | |
case 0: | |
switch ( ds.Get<uint8_t>() % 6 ) { | |
case 0: | |
if ( True ) CHECK_EQ(mp_exch(A.GetPtr(), B.GetPtr()), MP_OKAY); | |
break; | |
case 1: | |
if ( True ) CHECK_EQ(mp_exch(A.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 2: | |
if ( True ) CHECK_EQ(mp_exch(B.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 3: | |
if ( True ) CHECK_EQ(mp_exch(A.GetPtr(), D.GetPtr()), MP_OKAY); | |
break; | |
case 4: | |
if ( True ) CHECK_EQ(mp_exch(B.GetPtr(), D.GetPtr()), MP_OKAY); | |
break; | |
case 5: | |
if ( True ) CHECK_EQ(mp_exch(C.GetPtr(), D.GetPtr()), MP_OKAY); | |
break; | |
} | |
break; | |
case 1: | |
if ( True ) CHECK_EQ(mp_add(A.GetPtr(), B.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 2: | |
if ( True ) CHECK_EQ(mp_sub(A.GetPtr(), B.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 3: | |
if ( True ) CHECK_EQ(mp_div(A.GetPtr(), B.GetPtr(), C.GetPtr(), nullptr), MP_OKAY); | |
break; | |
case 4: | |
if ( True ) CHECK_EQ(mp_mul(A.GetPtr(), B.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 5: | |
if ( True ) CHECK_EQ(mp_sqr(A.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 6: | |
if ( True ) CHECK_EQ(mp_gcd(A.GetPtr(), B.GetPtr(), C.GetPtr()), MP_OKAY); | |
DEBUG_MSG("gcd(" << A << ", " << B << ") = " << C); | |
break; | |
case 7: | |
if ( True ) CHECK_EQ(mp_invmod(A.GetPtr(), B.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 8: | |
if ( True ) CHECK_EQ(mp_abs(A.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 9: | |
if ( True ) CHECK_EQ(mp_addmod(A.GetPtr(), B.GetPtr(), C.GetPtr(), D.GetPtr()), MP_OKAY); | |
break; | |
case 10: | |
if ( True ) CHECK_EQ(mp_mulmod(A.GetPtr(), B.GetPtr(), C.GetPtr(), D.GetPtr()), MP_OKAY); | |
break; | |
case 11: | |
if ( True ) CHECK_EQ(mp_sqrmod(A.GetPtr(), B.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 12: | |
if ( True ) A.Set(); | |
#if DEBUG | |
printf("Set\n"); | |
printf("=\n"); | |
printf("\t%s\n", A.ToString().c_str()); | |
#endif | |
break; | |
case 14: | |
{ | |
const auto ret = Compute(ds, numIter, std::nullopt, depth+1); | |
if ( ret == std::nullopt ) { | |
goto end; | |
} | |
A.Set(*ret); | |
#if DEBUG | |
printf("Compute\n"); | |
printf("=\n"); | |
printf("\t%s\n", A.ToString().c_str()); | |
#endif | |
} | |
break; | |
case 15: | |
if ( True ) CHECK_EQ(mp_mod(A.GetPtr(), B.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 16: | |
if ( True ) CHECK_EQ(mp_exptmod(A.GetPtr(), B.GetPtr(), C.GetPtr(), D.GetPtr()), MP_OKAY); | |
break; | |
case 17: | |
if ( True ) CHECK_EQ(mp_lcm(A.GetPtr(), B.GetPtr(), C.GetPtr()), MP_OKAY); | |
break; | |
case 18: | |
if ( True ) mp_rshb(A.GetPtr(), ds.Get<uint16_t>()); | |
break; | |
case 19: | |
if ( True ) CHECK_EQ(mp_mul_2d(A.GetPtr(), 1, B.GetPtr()), MP_OKAY); | |
break; | |
case 20: | |
if ( True ) CHECK_EQ(mp_submod(A.GetPtr(), B.GetPtr(), C.GetPtr(), D.GetPtr()), MP_OKAY); | |
break; | |
case 21: | |
True = mp_cmp(A.GetPtr(), B.GetPtr()) == MP_LT; | |
break; | |
case 22: | |
True = mp_cmp(A.GetPtr(), B.GetPtr()) == MP_EQ; | |
break; | |
case 23: | |
True = mp_cmp(A.GetPtr(), B.GetPtr()) == MP_GT; | |
break; | |
case 24: | |
True = false; | |
break; | |
case 25: | |
True = true; | |
break; | |
} | |
} | |
return A.ToString(); | |
} catch ( ... ) { } | |
end: | |
return std::nullopt; | |
} | |
fuzzing::datasource::Datasource dummy_ds(nullptr, 0); | |
Bignum smallest_delta(dummy_ds, "0"); | |
std::optional<std::string> Test(fuzzing::datasource::Datasource& ds, const std::string start_str, const std::string expected_str) { | |
size_t numIter = 0; | |
const auto ret = Compute(ds, &numIter, start_str); | |
if ( ret != std::nullopt ) { | |
try { | |
Bignum current_delta(dummy_ds, "0"); | |
Bignum result(dummy_ds, *ret); | |
Bignum expected(dummy_ds, expected_str); | |
if ( mp_sub(result.GetPtr(), expected.GetPtr(), current_delta.GetPtr()) != MP_OKAY ) { | |
abort(); | |
} | |
if ( mp_abs(current_delta.GetPtr(), current_delta.GetPtr()) != MP_OKAY ) { | |
abort(); | |
} | |
return current_delta.ToString(); | |
#if 0 | |
if ( current_delta.IsZero() ) return true; | |
if ( smallest_delta.IsZero() || mp_cmp(current_delta.GetPtr(), smallest_delta.GetPtr()) == MP_LT ) { | |
const auto s = current_delta.ToString(); | |
printf("smallest delta %s\n", s.c_str()); | |
smallest_delta.Set(s); | |
} | |
#endif | |
} catch ( ... ) { } | |
} | |
return std::nullopt; | |
} | |
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { | |
static size_t ret; | |
//Bignum A(ds, "869392137744"), B(ds), C(ds); | |
//if ( A.ToString() == "869392137744" ) abort(); | |
#if 0 | |
/* Find square root */ | |
const std::vector<std::pair<std::string, std::string>> tests = { | |
{"4", "2"}, | |
{"16", "4"}, | |
{"25", "5"}, | |
{"100", "10"}, | |
{"15129", "123"}, | |
{"9801", "99"} | |
}; | |
#endif | |
/* out = in * 2 / 3 */ | |
#if 0 | |
const std::vector<std::pair<std::string, std::string>> tests = { | |
{"4", "2"}, | |
{"40", "26"}, | |
{"99", "66"}, | |
{"123", "82"}, | |
}; | |
#endif | |
#if 0 | |
/* Find square root (2) */ | |
const std::vector<std::pair<std::string, std::string>> tests = { | |
{"4", "2"}, | |
{"81", "9"}, | |
{"256", "16"}, | |
{"529", "23"}, | |
{"900", "30"}, | |
{"1369", "37"}, | |
{"1936", "44"}, | |
{"2601", "51"}, | |
{"3364", "58"}, | |
{"4225", "65"}, | |
{"5184", "72"}, | |
{"6241", "79"}, | |
{"7396", "86"}, | |
{"8649", "93"}, | |
{"10000", "100"}, | |
{"11449", "107"}, | |
{"12996", "114"}, | |
{"14641", "121"}, | |
{"16384", "128"}, | |
{"18225", "135"}, | |
{"20164", "142"}, | |
{"22201", "149"}, | |
{"24336", "156"}, | |
{"26569", "163"}, | |
{"28900", "170"}, | |
{"31329", "177"}, | |
{"33856", "184"}, | |
{"36481", "191"}, | |
{"39204", "198"}, | |
{"42025", "205"}, | |
{"44944", "212"}, | |
{"47961", "219"}, | |
{"51076", "226"}, | |
{"54289", "233"}, | |
{"57600", "240"}, | |
{"61009", "247"}, | |
{"64516", "254"}, | |
{"68121", "261"}, | |
{"71824", "268"}, | |
{"75625", "275"}, | |
{"79524", "282"}, | |
{"83521", "289"}, | |
{"87616", "296"}, | |
{"91809", "303"}, | |
{"96100", "310"}, | |
{"100489", "317"}, | |
{"104976", "324"}, | |
{"109561", "331"}, | |
{"114244", "338"}, | |
{"119025", "345"}, | |
{"123904", "352"}, | |
{"128881", "359"}, | |
{"133956", "366"}, | |
{"139129", "373"}, | |
{"144400", "380"}, | |
{"149769", "387"}, | |
{"155236", "394"}, | |
{"160801", "401"}, | |
{"166464", "408"}, | |
{"172225", "415"}, | |
{"178084", "422"}, | |
{"184041", "429"}, | |
{"190096", "436"}, | |
{"196249", "443"}, | |
{"202500", "450"}, | |
{"208849", "457"}, | |
{"215296", "464"}, | |
{"221841", "471"}, | |
{"228484", "478"}, | |
{"235225", "485"}, | |
{"242064", "492"}, | |
{"249001", "499"}, | |
{"256036", "506"}, | |
{"263169", "513"}, | |
{"270400", "520"}, | |
{"277729", "527"}, | |
{"285156", "534"}, | |
{"292681", "541"}, | |
{"300304", "548"}, | |
{"308025", "555"}, | |
{"315844", "562"}, | |
{"323761", "569"}, | |
{"331776", "576"}, | |
{"339889", "583"}, | |
{"348100", "590"}, | |
{"356409", "597"}, | |
{"364816", "604"}, | |
{"373321", "611"}, | |
{"381924", "618"}, | |
{"390625", "625"}, | |
{"399424", "632"}, | |
{"408321", "639"}, | |
{"417316", "646"}, | |
{"426409", "653"}, | |
{"435600", "660"}, | |
{"444889", "667"}, | |
{"454276", "674"}, | |
{"463761", "681"}, | |
{"473344", "688"}, | |
{"483025", "695"}, | |
{"492804", "702"}, | |
{"502681", "709"}, | |
{"512656", "716"}, | |
{"522729", "723"}, | |
{"532900", "730"}, | |
{"543169", "737"}, | |
{"553536", "744"}, | |
{"564001", "751"}, | |
{"574564", "758"}, | |
{"585225", "765"}, | |
{"595984", "772"}, | |
{"606841", "779"}, | |
{"617796", "786"}, | |
{"628849", "793"}, | |
{"640000", "800"}, | |
{"651249", "807"}, | |
{"662596", "814"}, | |
{"674041", "821"}, | |
{"685584", "828"}, | |
{"697225", "835"}, | |
{"708964", "842"}, | |
{"720801", "849"}, | |
{"732736", "856"}, | |
{"744769", "863"}, | |
{"756900", "870"}, | |
{"769129", "877"}, | |
{"781456", "884"}, | |
{"793881", "891"}, | |
{"806404", "898"}, | |
{"819025", "905"}, | |
{"831744", "912"}, | |
{"844561", "919"}, | |
{"857476", "926"}, | |
{"870489", "933"}, | |
{"883600", "940"}, | |
{"896809", "947"}, | |
{"910116", "954"}, | |
{"923521", "961"}, | |
{"937024", "968"}, | |
{"950625", "975"}, | |
{"964324", "982"}, | |
{"978121", "989"}, | |
{"992016", "996"}, | |
}; | |
#endif | |
#if 0 | |
/* Divide by 2 */ | |
const std::vector<std::pair<std::string, std::string>> tests = { | |
{"4", "2"}, | |
{"8", "4"}, | |
{"10", "5"}, | |
{"20", "10"} | |
}; | |
#endif | |
#if 0 | |
/* Divide by 1000 */ | |
const std::vector<std::pair<std::string, std::string>> tests = { | |
{"1", "1000"}, | |
{"2", "2000"}, | |
{"10", "10000"}, | |
{"30", "30000"} | |
}; | |
#endif | |
size_t num = 0; | |
Bignum aggregate_delta(dummy_ds, "0"); | |
for (const auto& pair : tests) { | |
fuzzing::datasource::Datasource ds(data, size); | |
const auto current_delta_str = Test(ds, pair.first, pair.second); | |
if ( current_delta_str == std::nullopt ) { | |
continue; | |
} | |
Bignum current_delta(dummy_ds, *current_delta_str); | |
if ( mp_add(aggregate_delta.GetPtr(), current_delta.GetPtr(), aggregate_delta.GetPtr()) != MP_OKAY ) { | |
return 0; | |
} | |
num++; | |
} | |
if ( num != tests.size() ) return 0; | |
if ( smallest_delta.IsZero() || mp_cmp(aggregate_delta.GetPtr(), smallest_delta.GetPtr()) == MP_LT ) { | |
const auto s = aggregate_delta.ToString(); | |
fprintf(stderr, "smallest aggregate delta %s\n", s.c_str()); | |
smallest_delta.Set(s); | |
ret++; | |
} | |
if ( aggregate_delta.ToString() == "2" ) abort(); | |
if ( aggregate_delta.IsZero() ) abort(); | |
end: | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment