Add a basic unittest framework + a compute KZG proof test (#96)

* Add tinytest.h testing framework

from https://github.com/joewalnes/tinytest/

* Add a basic compute_kzg_proof() test
This commit is contained in:
George Kadianakis 2023-01-30 14:40:12 +01:00 committed by GitHub
parent e4f280f17f
commit 98aa54a996
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 222 additions and 3 deletions

2
.gitignore vendored
View File

@ -1,4 +1,6 @@
test_c_kzg_4844
*.o
*.s
*.a
*.out
inc/blst.h*

View File

@ -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

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "blst.h"
#include "c_kzg_4844.h"
#include <inttypes.h>
@ -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);
/**

View File

@ -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

81
src/test_c_kzg_4844.c Normal file
View File

@ -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 <stdio.h>
#include <string.h>
#include <assert.h>
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();
}

112
src/tinytest.h Normal file
View File

@ -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 <joe@walnes.com> http://joewalnes.com
*/
#ifndef _TINYTEST_INCLUDED
#define _TINYTEST_INCLUDED
#include <stdio.h>
#include <stdlib.h>
/* 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