Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guidovranken/072be361a0aaa2b7b70dc81d5e876168 to your computer and use it in GitHub Desktop.
Save guidovranken/072be361a0aaa2b7b70dc81d5e876168 to your computer and use it in GitHub Desktop.
#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