diff --git a/.gitignore b/.gitignore index 6d15fee..f1f6ce5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +test_c_kzg_4844 *.o +*.s *.a *.out inc/blst.h* diff --git a/src/Makefile b/src/Makefile index 4512e0c..39d5fb0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -25,3 +25,13 @@ blst: # Make sure c_kzg_4844.o is built and copy it for the NodeJS bindings lib: c_kzg_4844.o Makefile cp *.o ../bindings/node.js + +test_c_kzg_4844: test_c_kzg_4844.c c_kzg_4844.c Makefile + ${CLANG_EXECUTABLE} -Wall -I$(INCLUDE_DIRS) -DFIELD_ELEMENTS_PER_BLOB=$(FIELD_ELEMENTS_PER_BLOB) -DUNIT_TESTS $(CFLAGS) -c c_kzg_4844.c -o test_c_kzg_4844.o + ${CLANG_EXECUTABLE} -Wall -I$(INCLUDE_DIRS) -DFIELD_ELEMENTS_PER_BLOB=$(FIELD_ELEMENTS_PER_BLOB) $(CFLAGS) test_c_kzg_4844.o -L ../lib -lblst -o test_c_kzg_4844 $< + +test: test_c_kzg_4844 + ./test_c_kzg_4844 + +clean: + rm -f *.o test_c_kzg_4844 diff --git a/src/c_kzg_4844.c b/src/c_kzg_4844.c index 43ee2d1..765ac88 100644 --- a/src/c_kzg_4844.c +++ b/src/c_kzg_4844.c @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "blst.h" #include "c_kzg_4844.h" #include @@ -27,6 +28,12 @@ #define CHECK(cond) \ if (!(cond)) return C_KZG_BADARGS +#ifdef UNIT_TESTS +#define STATIC +#else /* !defined(UNIT_TESTS) */ +#define STATIC static +#endif /* defined(UNIT_TESTS) */ + /////////////////////////////////////////////////////////////////////////////// // Types /////////////////////////////////////////////////////////////////////////////// @@ -492,7 +499,7 @@ static void bytes_from_g1(Bytes48 *out, const g1_t *in) { * @param[out] out A 32-byte array to store the serialized field element * @param[in] in The field element to be serialized */ -static void bytes_from_bls_field(Bytes32 *out, const fr_t *in) { +STATIC void bytes_from_bls_field(Bytes32 *out, const fr_t *in) { blst_scalar_from_fr((blst_scalar*)out->bytes, in); } @@ -602,7 +609,7 @@ static C_KZG_RET bit_reversal_permutation(void *values, size_t size, uint64_t n) * @param[out] out The field element to store the result * @param[in] bytes A 32-byte array containing the input */ -static void hash_to_bls_field(fr_t *out, const Bytes32 *b) { +STATIC void hash_to_bls_field(fr_t *out, const Bytes32 *b) { blst_scalar tmp; blst_scalar_from_lendian(&tmp, b->bytes); blst_fr_from_scalar(out, &tmp); @@ -984,7 +991,7 @@ C_KZG_RET blob_to_kzg_commitment(KZGCommitment *out, const Blob *blob, const KZG } /* Forward function declaration */ -static C_KZG_RET verify_kzg_proof_impl(bool *out, const g1_t *commitment, const fr_t *x, const fr_t *y, +static C_KZG_RET verify_kzg_proof_impl(bool *out, const g1_t *commitment, const fr_t *z, const fr_t *y, const g1_t *proof, const KZGSettings *ks); /** diff --git a/src/c_kzg_4844.h b/src/c_kzg_4844.h index e408d3c..5370877 100644 --- a/src/c_kzg_4844.h +++ b/src/c_kzg_4844.h @@ -124,6 +124,13 @@ C_KZG_RET compute_kzg_proof(KZGProof *out, const Bytes32 *z_bytes, const KZGSettings *s); +#ifdef UNIT_TESTS + +void hash_to_bls_field(fr_t *out, const Bytes32 *b); +void bytes_from_bls_field(Bytes32 *out, const fr_t *in); + +#endif + #ifdef __cplusplus } #endif diff --git a/src/test_c_kzg_4844.c b/src/test_c_kzg_4844.c new file mode 100644 index 0000000..666f202 --- /dev/null +++ b/src/test_c_kzg_4844.c @@ -0,0 +1,81 @@ +/* Tests for myfunctions.c, using TinyTest. */ + +#define UNIT_TESTS + +#include "tinytest.h" +#include "blst.h" + +#include "c_kzg_4844.h" +#include +#include +#include + +KZGSettings s; + +void load_setup() { + FILE *fp; + C_KZG_RET ret; + fp = fopen("trusted_setup.txt", "rb"); + + ret = load_trusted_setup_file(&s, fp); + assert(ret == C_KZG_OK); + + fclose(fp); +} + +void get_32_rand_bytes(uint8_t *out) { + static uint64_t seed = 0; + seed++; + blst_sha256(out, (uint8_t*)&seed, sizeof(seed)); +} + +void get_rand_field_element(Bytes32 *out) { + fr_t tmp; + Bytes32 tmp_rand; + + memset(out, 0, sizeof(Bytes32)); + + // Take 32 random bytes, make them an Fr, and then turn the Fr back to a bytes array + get_32_rand_bytes((uint8_t *) &tmp_rand); + hash_to_bls_field(&tmp, &tmp_rand); + bytes_from_bls_field(out, &tmp); +} + +void get_rand_blob(Blob *out) { + memset(out, 0, sizeof(Blob)); + + uint8_t *blob_bytes = (uint8_t *) out; + for (int i = 0; i < 128; i++) { + get_rand_field_element((Bytes32 *)&blob_bytes[i * 32]); + } +} + +void test_compute_kzg_proof() { + C_KZG_RET ret; + Bytes48 proof; + Bytes32 z; + KZGCommitment c; + Blob blob; + + get_rand_field_element(&z); + get_rand_blob(&blob); + + ret = blob_to_kzg_commitment(&c, &blob, &s); + ASSERT_EQUALS(ret, C_KZG_OK); + + ret = compute_kzg_proof(&proof, &blob, &z, &s); + ASSERT_EQUALS(ret, C_KZG_OK); + + // XXX now verify it! +} + +/* test runner */ +int main() +{ + load_setup(); + + RUN(test_compute_kzg_proof); + + free_trusted_setup(&s); + return TEST_REPORT(); +} diff --git a/src/tinytest.h b/src/tinytest.h new file mode 100644 index 0000000..81b5f6a --- /dev/null +++ b/src/tinytest.h @@ -0,0 +1,112 @@ +/* TinyTest: A really really really tiny and simple no-hassle C unit-testing framework. + * + * Features: + * - No library dependencies. Not even itself. Just a header file. + * - Simple ANSI C. Should work with virtually every C or C++ compiler on + * virtually any platform. + * - Reports assertion failures, including expressions and line numbers. + * - Stops test on first failed assertion. + * - ANSI color output for maximum visibility. + * - Easy to embed in apps for runtime tests (e.g. environment tests). + * + * Example Usage: + * + * #include "tinytest.h" + * #include "mylib.h" + * + * void test_sheep() + * { + * ASSERT("Sheep are cool", are_sheep_cool()); + * ASSERT_EQUALS(4, sheep.legs); + * } + * + * void test_cheese() + * { + * ASSERT("Cheese is tangy", cheese.tanginess > 0); + * ASSERT_STRING_EQUALS("Wensleydale", cheese.name); + * } + * + * int main() + * { + * RUN(test_sheep); + * RUN(test_cheese); + * return TEST_REPORT(); + * } + * + * To run the tests, compile the tests as a binary and run it. + * + * Project home page: http://github.com/joewalnes/tinytest + * + * 2010, -Joe Walnes http://joewalnes.com + */ + +#ifndef _TINYTEST_INCLUDED +#define _TINYTEST_INCLUDED + +#include +#include + +/* Main assertion method */ +#define ASSERT(msg, expression) if (!tt_assert(__FILE__, __LINE__, (msg), (#expression), (expression) ? 1 : 0)) return + +/* Convenient assertion methods */ +/* TODO: Generate readable error messages for assert_equals or assert_str_equals */ +#define ASSERT_EQUALS(expected, actual) ASSERT((#actual), (expected) == (actual)) +#define ASSERT_STRING_EQUALS(expected, actual) ASSERT((#actual), strcmp((expected),(actual)) == 0) + +/* Run a test() function */ +#define RUN(test_function) tt_execute((#test_function), (test_function)) +#define TEST_REPORT() tt_report() + +#define TT_COLOR_CODE 0x1B +#define TT_COLOR_RED "[1;31m" +#define TT_COLOR_GREEN "[1;32m" +#define TT_COLOR_RESET "[0m" + +int tt_passes = 0; +int tt_fails = 0; +int tt_current_test_failed = 0; +const char* tt_current_msg = NULL; +const char* tt_current_expression = NULL; +const char* tt_current_file = NULL; +int tt_current_line = 0; + +void tt_execute(const char* name, void (*test_function)()) +{ + tt_current_test_failed = 0; + test_function(); + if (tt_current_test_failed) { + printf("failure: %s:%d: In test %s():\n %s (%s)\n", + tt_current_file, tt_current_line, name, tt_current_msg, tt_current_expression); + tt_fails++; + } else { + tt_passes++; + } +} + +int tt_assert(const char* file, int line, const char* msg, const char* expression, int pass) +{ + tt_current_msg = msg; + tt_current_expression = expression; + tt_current_file = file; + tt_current_line = line; + tt_current_test_failed = !pass; + return pass; +} + +int tt_report(void) +{ + if (tt_fails) { + printf("%c%sFAILED%c%s [%s] (passed:%d, failed:%d, total:%d)\n", + TT_COLOR_CODE, TT_COLOR_RED, TT_COLOR_CODE, TT_COLOR_RESET, + tt_current_file, tt_passes, tt_fails, tt_passes + tt_fails); + return -1; + } else { + printf("%c%sPASSED%c%s [%s] (total:%d)\n", + TT_COLOR_CODE, TT_COLOR_GREEN, TT_COLOR_CODE, TT_COLOR_RESET, + tt_current_file, tt_passes); + return 0; + } +} + +#endif