Revamp error handling and memory management

This commit is contained in:
Ben Edgington 2021-02-14 14:20:03 +00:00
parent d22bbcca62
commit cfe5fa6e49
12 changed files with 249 additions and 77 deletions

View File

@ -46,9 +46,23 @@ typedef enum {
printf("\n%s:%d: Failed ASSERT: %s\n", __FILE__, __LINE__, #cond); \ printf("\n%s:%d: Failed ASSERT: %s\n", __FILE__, __LINE__, #cond); \
abort(); \ abort(); \
} }
#define TRY(result) \
{ \
C_KZG_RET ret = (result); \
if (ret != C_KZG_OK) { \
printf("\n%s:%d: Failed TRY: %s, result = %d\n", __FILE__, __LINE__, #result, ret); \
abort(); \
} \
}
#else #else
#define ASSERT(cond, ret) \ #define ASSERT(cond, ret) \
if (!(cond)) return (ret) if (!(cond)) return (ret)
#define TRY(result) \
{ \
C_KZG_RET ret = (result); \
if (ret == C_KZG_MALLOC) return ret; \
if (ret != C_KZG_OK) return C_KZG_ERROR; \
}
#endif // DEBUG #endif // DEBUG
/** @def ASSERT /** @def ASSERT
@ -56,7 +70,8 @@ typedef enum {
* Handle errors. * Handle errors.
* *
* This macro comes in two versions according to whether `DEBUG` is defined or not (`-DDEBUG` compiler flag). * This macro comes in two versions according to whether `DEBUG` is defined or not (`-DDEBUG` compiler flag).
* - `DEBUG` is undefined: when @p cond is false, return from the function with the value @p ret, otherwise continue. * - `DEBUG` is undefined: when @p cond is false, return from the current function with the value @p ret, otherwise
* continue.
* - `DEBUG` is defined: when @p cond is false, print file and line number information and abort the run. This is very * - `DEBUG` is defined: when @p cond is false, print file and line number information and abort the run. This is very
* useful for dubugging. The @p ret parameter is ignored in this case. * useful for dubugging. The @p ret parameter is ignored in this case.
* *
@ -64,4 +79,16 @@ typedef enum {
* @param ret The return code to be returned in case the condition is false * @param ret The return code to be returned in case the condition is false
*/ */
/** @def TRY
*
* Handle errors.
*
* This macro comes in two versions according to whether `DEBUG` is defined or not (`-DDEBUG` compiler flag).
* - `DEBUG` is undefined: if the @p result is not `C_KZG_OK`, return immediately with either `C_KZG_MALLOC` or
* `C_KZG_ERROR`. Otherwise continue.
* - `DEBUG` is defined: if @p result is not `C_KZG_OK`, print file and line number information and abort the run.
* This is very useful for dubugging.
*
* @param result The function call result to be tested
*/
#endif // C_KZG_H #endif // C_KZG_H

View File

@ -20,7 +20,6 @@
* Utilities useful across the library. * Utilities useful across the library.
*/ */
#include <stdlib.h> // malloc
#include "c_kzg_util.h" #include "c_kzg_util.h"
/** /**

View File

@ -16,6 +16,7 @@
/** @file c_kzg_util.c */ /** @file c_kzg_util.c */
#include <stdlib.h> // free()
#include "c_kzg.h" #include "c_kzg.h"
C_KZG_RET c_kzg_malloc(void **p, size_t n); C_KZG_RET c_kzg_malloc(void **p, size_t n);

View File

@ -20,7 +20,6 @@
* Code shared between the FFTs over field elements and FFTs over G1 group elements. * Code shared between the FFTs over field elements and FFTs over G1 group elements.
*/ */
#include <stdlib.h> // free()
#include "fft_common.h" #include "fft_common.h"
#include "blst_util.h" #include "blst_util.h"
#include "c_kzg_util.h" #include "c_kzg_util.h"
@ -73,7 +72,8 @@ C_KZG_RET expand_root_of_unity(blst_fr *out, const blst_fr *root, uint64_t width
* `max_width` is the maximum size of FFT that can be calculated with these settings, and is a power of two by * `max_width` is the maximum size of FFT that can be calculated with these settings, and is a power of two by
* construction. The same settings may be used to calculated FFTs of smaller power sizes. * construction. The same settings may be used to calculated FFTs of smaller power sizes.
* *
* @remark This structure *must* be deallocated after use by calling #free_fft_settings. * @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_fft_settings.
* @remark These settings may be used for FFTs on both field elements and G1 group elements. * @remark These settings may be used for FFTs on both field elements and G1 group elements.
* *
* @param[out] fs The new settings * @param[out] fs The new settings
@ -90,16 +90,11 @@ C_KZG_RET new_fft_settings(FFTSettings *fs, unsigned int max_scale) {
blst_fr_from_uint64(&fs->root_of_unity, scale2_root_of_unity[max_scale]); blst_fr_from_uint64(&fs->root_of_unity, scale2_root_of_unity[max_scale]);
// Allocate space for the roots of unity // Allocate space for the roots of unity
ASSERT(c_kzg_malloc((void **)&fs->expanded_roots_of_unity, TRY(c_kzg_malloc((void **)&fs->expanded_roots_of_unity, (fs->max_width + 1) * sizeof *fs->expanded_roots_of_unity));
(fs->max_width + 1) * sizeof *fs->expanded_roots_of_unity) == C_KZG_OK, TRY(c_kzg_malloc((void **)&fs->reverse_roots_of_unity, (fs->max_width + 1) * sizeof *fs->reverse_roots_of_unity));
C_KZG_MALLOC);
ASSERT(c_kzg_malloc((void **)&fs->reverse_roots_of_unity,
(fs->max_width + 1) * sizeof *fs->reverse_roots_of_unity) == C_KZG_OK,
C_KZG_MALLOC);
// Populate the roots of unity // Populate the roots of unity
ASSERT(expand_root_of_unity(fs->expanded_roots_of_unity, &fs->root_of_unity, fs->max_width) == C_KZG_OK, TRY(expand_root_of_unity(fs->expanded_roots_of_unity, &fs->root_of_unity, fs->max_width));
C_KZG_ERROR);
// Populate reverse roots of unity // Populate reverse roots of unity
for (uint64_t i = 0; i <= fs->max_width; i++) { for (uint64_t i = 0; i <= fs->max_width; i++) {

View File

@ -27,6 +27,7 @@
#include "fft_fr.h" #include "fft_fr.h"
#include "blst_util.h" #include "blst_util.h"
#include "c_kzg_util.h"
/** /**
* Slow Fourier Transform. * Slow Fourier Transform.
@ -112,3 +113,37 @@ C_KZG_RET fft_fr(blst_fr *out, const blst_fr *in, bool inverse, uint64_t n, cons
} }
return C_KZG_OK; return C_KZG_OK;
} }
/**
* Wrapper for #fft_fr that allocates memory for the output.
*
* @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_fft_fr.
*
* @param[out] out The results (array of length @p n)
* @param[in] in The input data (array of length @p n)
* @param[in] inverse `false` for forward transform, `true` for inverse transform
* @param[in] n Length of the FFT, must be a power of two
* @param[in] fs Pointer to previously initialised FFTSettings structure with `max_width` at least @p n.
* @retval C_CZK_OK All is well
* @retval C_CZK_BADARGS Invalid parameters were supplied
* @retval C_CZK_MALLOC Memory allocation failed
*/
C_KZG_RET new_fft_fr(blst_fr **out, const blst_fr *in, bool inverse, uint64_t n, const FFTSettings *fs) {
C_KZG_RET ret;
TRY(c_kzg_malloc((void **)out, n * sizeof **out));
ret = fft_fr(*out, in, inverse, n, fs);
if (ret == C_KZG_BADARGS) {
free_fft_fr(*out);
}
return ret;
}
/**
* Recover memory allocated by #new_fft_fr.
*
* @param x The array to be freed
*/
void free_fft_fr(blst_fr *x) {
free(x);
}

View File

@ -23,3 +23,5 @@ void fft_fr_slow(blst_fr *out, const blst_fr *in, uint64_t stride, const blst_fr
void fft_fr_fast(blst_fr *out, const blst_fr *in, uint64_t stride, const blst_fr *roots, uint64_t roots_stride, void fft_fr_fast(blst_fr *out, const blst_fr *in, uint64_t stride, const blst_fr *roots, uint64_t roots_stride,
uint64_t n); uint64_t n);
C_KZG_RET fft_fr(blst_fr *out, const blst_fr *in, bool inverse, uint64_t n, const FFTSettings *fs); C_KZG_RET fft_fr(blst_fr *out, const blst_fr *in, bool inverse, uint64_t n, const FFTSettings *fs);
C_KZG_RET new_fft_fr(blst_fr **out, const blst_fr *in, bool inverse, uint64_t n, const FFTSettings *fs);
void free_fft_fr(blst_fr *x);

View File

@ -27,6 +27,7 @@
#include "fft_g1.h" #include "fft_g1.h"
#include "blst_util.h" #include "blst_util.h"
#include "c_kzg_util.h"
/** /**
* Slow Fourier Transform. * Slow Fourier Transform.
@ -113,3 +114,37 @@ C_KZG_RET fft_g1(blst_p1 *out, const blst_p1 *in, bool inverse, uint64_t n, cons
} }
return C_KZG_OK; return C_KZG_OK;
} }
/**
* Wrapper for #fft_g1 that allocates memory for the output.
*
* @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_fft_g1.
*
* @param[out] out The results (array of length @p n)
* @param[in] in The input data (array of length @p n)
* @param[in] inverse `false` for forward transform, `true` for inverse transform
* @param[in] n Length of the FFT, must be a power of two
* @param[in] fs Pointer to previously initialised FFTSettings structure with `max_width` at least @p n.
* @retval C_CZK_OK All is well
* @retval C_CZK_BADARGS Invalid parameters were supplied
* @retval C_CZK_MALLOC Memory allocation failed
*/
C_KZG_RET new_fft_g1(blst_p1 **out, const blst_p1 *in, bool inverse, uint64_t n, const FFTSettings *fs) {
C_KZG_RET ret;
TRY(c_kzg_malloc((void **)out, n * sizeof **out));
ret = fft_g1(*out, in, inverse, n, fs);
if (ret == C_KZG_BADARGS) {
free_fft_g1(*out);
}
return ret;
}
/**
* Recover memory allocated by #new_fft_g1.
*
* @param x The array to be freed
*/
void free_fft_g1(blst_p1 *x) {
free(x);
}

View File

@ -23,3 +23,5 @@ void fft_g1_slow(blst_p1 *out, const blst_p1 *in, uint64_t stride, const blst_fr
void fft_g1_fast(blst_p1 *out, const blst_p1 *in, uint64_t stride, const blst_fr *roots, uint64_t roots_stride, void fft_g1_fast(blst_p1 *out, const blst_p1 *in, uint64_t stride, const blst_fr *roots, uint64_t roots_stride,
uint64_t n); uint64_t n);
C_KZG_RET fft_g1(blst_p1 *out, const blst_p1 *in, bool inverse, uint64_t n, const FFTSettings *fs); C_KZG_RET fft_g1(blst_p1 *out, const blst_p1 *in, bool inverse, uint64_t n, const FFTSettings *fs);
C_KZG_RET new_fft_g1(blst_p1 **out, const blst_p1 *in, bool inverse, uint64_t n, const FFTSettings *fs);
void free_fft_g1(blst_p1 *x);

View File

@ -21,7 +21,6 @@
* paper](https://github.com/khovratovich/Kate/blob/master/Kate_amortized.pdf). * paper](https://github.com/khovratovich/Kate/blob/master/Kate_amortized.pdf).
*/ */
#include <stdlib.h> // free()
#include <string.h> // memcpy() #include <string.h> // memcpy()
#include "fk20_proofs.h" #include "fk20_proofs.h"
#include "fft_g1.h" #include "fft_g1.h"
@ -109,8 +108,6 @@ C_KZG_RET reverse_bit_order(void *values, size_t size, uint64_t n) {
* The first part of the Toeplitz matrix multiplication algorithm: the Fourier * The first part of the Toeplitz matrix multiplication algorithm: the Fourier
* transform of the vector @p x extended. * transform of the vector @p x extended.
* *
* Used in #new_fk20_single_settings to calculate `x_ext_fft`.
*
* @param[out] out The FFT of the extension of @p x, size @p n * 2 * @param[out] out The FFT of the extension of @p x, size @p n * 2
* @param[in] x The input vector, size @p n * @param[in] x The input vector, size @p n
* @param[in] n The length of the input vector @p x * @param[in] n The length of the input vector @p x
@ -123,8 +120,7 @@ C_KZG_RET toeplitz_part_1(blst_p1 *out, const blst_p1 *x, uint64_t n, const FFTS
uint64_t n2 = n * 2; uint64_t n2 = n * 2;
blst_p1 *x_ext; blst_p1 *x_ext;
ASSERT(c_kzg_malloc((void **)&x_ext, n2 * sizeof *x_ext) == C_KZG_OK, C_KZG_MALLOC); TRY(c_kzg_malloc((void **)&x_ext, n2 * sizeof *x_ext));
for (uint64_t i = 0; i < n; i++) { for (uint64_t i = 0; i < n; i++) {
x_ext[i] = x[i]; x_ext[i] = x[i];
} }
@ -132,12 +128,41 @@ C_KZG_RET toeplitz_part_1(blst_p1 *out, const blst_p1 *x, uint64_t n, const FFTS
x_ext[i] = g1_identity; x_ext[i] = g1_identity;
} }
ASSERT(fft_g1(out, x_ext, false, n2, fs) == C_KZG_OK, C_KZG_ERROR); TRY(fft_g1(out, x_ext, false, n2, fs));
free(x_ext); free(x_ext);
return C_KZG_OK; return C_KZG_OK;
} }
/**
* Wrapper for #toeplitz_part_1 that allocates memory for the output.
*
* @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_toeplitz_part_1.
*
* @param[out] out The FFT of the extension of @p x, size @p n * 2
* @param[in] x The input vector, size @p n
* @param[in] n The length of the input vector @p x
* @param[in] fs The FFT settings previously initialised with #new_fft_settings
* @retval C_CZK_OK All is well
* @retval C_CZK_ERROR An internal error occurred
* @retval C_CZK_MALLOC Memory allocation failed
*/
C_KZG_RET new_toeplitz_part_1(blst_p1 **out, const blst_p1 *x, uint64_t n, const FFTSettings *fs) {
TRY(c_kzg_malloc((void **)out, n * 2 * sizeof **out));
TRY(toeplitz_part_1(*out, x, n, fs));
return C_KZG_OK;
}
/**
* Recover memory allocated by #new_toeplitz_part_1.
*
* @param x The array to be freed
*/
void free_toeplitz_part_1(blst_p1 *x) {
free(x);
}
/** /**
* The second part of the Toeplitz matrix multiplication algorithm. * The second part of the Toeplitz matrix multiplication algorithm.
* *
@ -153,21 +178,50 @@ C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20S
blst_fr *toeplitz_coeffs_fft; blst_fr *toeplitz_coeffs_fft;
ASSERT(toeplitz_coeffs->length == fk->x_ext_fft_len, C_KZG_BADARGS); ASSERT(toeplitz_coeffs->length == fk->x_ext_fft_len, C_KZG_BADARGS);
ASSERT(c_kzg_malloc((void **)&toeplitz_coeffs_fft, toeplitz_coeffs->length * sizeof *toeplitz_coeffs_fft) ==
C_KZG_OK,
C_KZG_MALLOC);
ASSERT(fft_fr(toeplitz_coeffs_fft, toeplitz_coeffs->coeffs, false, toeplitz_coeffs->length, fk->ks->fs) == C_KZG_OK, TRY(new_fft_fr(&toeplitz_coeffs_fft, toeplitz_coeffs->coeffs, false, toeplitz_coeffs->length, fk->ks->fs));
C_KZG_ERROR);
for (uint64_t i = 0; i < toeplitz_coeffs->length; i++) { for (uint64_t i = 0; i < toeplitz_coeffs->length; i++) {
p1_mul(&out[i], &fk->x_ext_fft[i], &toeplitz_coeffs_fft[i]); p1_mul(&out[i], &fk->x_ext_fft[i], &toeplitz_coeffs_fft[i]);
} }
free(toeplitz_coeffs_fft); free_fft_fr(toeplitz_coeffs_fft);
return C_KZG_OK; return C_KZG_OK;
} }
/**
* Wrapper for #toeplitz_part_2 that allocates memory for the output.
*
* @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_toeplitz_part_2.
*
* @param[out] out Array of G1 group elements, length `n`
* @param[in] toeplitz_coeffs Toeplitz coefficients, a polynomial length `n`
* @param[in] fk FK20 single settings previously initialised by #new_fk20_single_settings
* @retval C_CZK_OK All is well
* @retval C_CZK_BADARGS Invalid parameters were supplied
* @retval C_CZK_ERROR An internal error occurred
* @retval C_CZK_MALLOC Memory allocation failed
*/
C_KZG_RET new_toeplitz_part_2(blst_p1 **out, const poly *toeplitz_coeffs, const FK20SingleSettings *fk) {
C_KZG_RET ret;
TRY(c_kzg_malloc((void **)out, toeplitz_coeffs->length * sizeof **out));
ret = toeplitz_part_2(*out, toeplitz_coeffs, fk);
if (ret == C_KZG_BADARGS) {
free_toeplitz_part_2(*out);
}
return ret;
}
/**
* Recover memory allocated by #new_toeplitz_part_2.
*
* @param x The array to be freed
*/
void free_toeplitz_part_2(blst_p1 *x) {
free(x);
}
/** /**
* The third part of the Toeplitz matrix multiplication algorithm: transform back and zero the top half. * The third part of the Toeplitz matrix multiplication algorithm: transform back and zero the top half.
* *
@ -181,7 +235,7 @@ C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20S
C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk) { C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk) {
uint64_t n = n2 / 2; uint64_t n = n2 / 2;
ASSERT(fft_g1(out, h_ext_fft, true, n2, fk->ks->fs) == C_KZG_OK, C_KZG_ERROR); TRY(fft_g1(out, h_ext_fft, true, n2, fk->ks->fs));
// Zero the second half of h // Zero the second half of h
for (uint64_t i = n; i < n2; i++) { for (uint64_t i = n; i < n2; i++) {
@ -191,10 +245,40 @@ C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, c
return C_KZG_OK; return C_KZG_OK;
} }
/**
* Wrapper for #toeplitz_part_3 that allocates memory for the output.
*
* @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_toeplitz_part_3.
*
* @param[out] out Array of G1 group elements, length @p n2
* @param[in] h_ext_fft FFT of the extended `h` values, length @p n2
* @param[in] n2 Size of the arrays
* @param[in] fk FK20 single settings previously initialised by #new_fk20_single_settings
* @retval C_CZK_OK All is well
* @retval C_CZK_ERROR An internal error occurred
* @retval C_CZK_MALLOC Memory allocation failed
*/
C_KZG_RET new_toeplitz_part_3(blst_p1 **out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk) {
TRY(c_kzg_malloc((void **)out, n2 * sizeof **out));
TRY(toeplitz_part_3(*out, h_ext_fft, n2, fk));
return C_KZG_OK;
}
/**
* Recover memory allocated by #new_toeplitz_part_3.
*
* @param x The array to be freed
*/
void free_toeplitz_part_3(blst_p1 *x) {
free(x);
}
/** /**
* Reorder and extend polynomial coefficients for the toeplitz method. * Reorder and extend polynomial coefficients for the toeplitz method.
* *
* @remark Allocates space for the return polynomial that needs to be freed by calling #free_poly. * @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_toeplitz_coeffs_step.
* *
* @param[out] out The reordered polynomial, size `n * 2` * @param[out] out The reordered polynomial, size `n * 2`
* @param[in] in The input polynomial, size `n` * @param[in] in The input polynomial, size `n`
@ -204,7 +288,7 @@ C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, c
C_KZG_RET new_toeplitz_coeffs_step(poly *out, const poly *in) { C_KZG_RET new_toeplitz_coeffs_step(poly *out, const poly *in) {
uint64_t n = in->length, n2 = n * 2; uint64_t n = in->length, n2 = n * 2;
ASSERT(new_poly(out, n2) == C_KZG_OK, C_KZG_MALLOC); TRY(new_poly(out, n2));
out->coeffs[0] = in->coeffs[n - 1]; out->coeffs[0] = in->coeffs[n - 1];
for (uint64_t i = 1; i <= n + 1; i++) { for (uint64_t i = 1; i <= n + 1; i++) {
@ -249,25 +333,18 @@ C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, const FK20SingleSettin
uint64_t n = p->length, n2 = n * 2; uint64_t n = p->length, n2 = n * 2;
blst_p1 *h, *h_ext_fft; blst_p1 *h, *h_ext_fft;
poly toeplitz_coeffs; poly toeplitz_coeffs;
C_KZG_RET ret;
ASSERT(n2 <= fk->ks->fs->max_width, C_KZG_BADARGS); ASSERT(n2 <= fk->ks->fs->max_width, C_KZG_BADARGS);
ASSERT(is_power_of_two(n), C_KZG_BADARGS); ASSERT(is_power_of_two(n), C_KZG_BADARGS);
ASSERT(new_toeplitz_coeffs_step(&toeplitz_coeffs, p) == C_KZG_OK, C_KZG_MALLOC); TRY(new_toeplitz_coeffs_step(&toeplitz_coeffs, p));
TRY(new_toeplitz_part_2(&h_ext_fft, &toeplitz_coeffs, fk));
TRY(new_toeplitz_part_3(&h, h_ext_fft, n2, fk));
TRY(fft_g1(out, h, false, n2, fk->ks->fs));
ASSERT(c_kzg_malloc((void **)&h_ext_fft, toeplitz_coeffs.length * sizeof *h_ext_fft) == C_KZG_OK, C_KZG_MALLOC);
ASSERT((ret = toeplitz_part_2(h_ext_fft, &toeplitz_coeffs, fk)) == C_KZG_OK,
ret == C_KZG_MALLOC ? ret : C_KZG_ERROR);
ASSERT(c_kzg_malloc((void **)&h, toeplitz_coeffs.length * sizeof *h) == C_KZG_OK, C_KZG_MALLOC);
ASSERT(toeplitz_part_3(h, h_ext_fft, n2, fk) == C_KZG_OK, C_KZG_ERROR);
ASSERT(fft_g1(out, h, false, n2, fk->ks->fs) == C_KZG_OK, C_KZG_ERROR);
free(h);
free(h_ext_fft);
free_toeplitz_coeffs_step(&toeplitz_coeffs); free_toeplitz_coeffs_step(&toeplitz_coeffs);
free_toeplitz_part_2(h_ext_fft);
free_toeplitz_part_3(h);
return C_KZG_OK; return C_KZG_OK;
} }
@ -293,8 +370,8 @@ C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, const FK20SingleSett
ASSERT(n2 <= fk->ks->fs->max_width, C_KZG_BADARGS); ASSERT(n2 <= fk->ks->fs->max_width, C_KZG_BADARGS);
ASSERT(is_power_of_two(n), C_KZG_BADARGS); ASSERT(is_power_of_two(n), C_KZG_BADARGS);
ASSERT(fk20_single_da_opt(out, p, fk) == C_KZG_OK, C_KZG_ERROR); TRY(fk20_single_da_opt(out, p, fk));
ASSERT(reverse_bit_order(out, sizeof out[0], n2) == C_KZG_OK, C_KZG_ERROR); TRY(reverse_bit_order(out, sizeof out[0], n2));
return C_KZG_OK; return C_KZG_OK;
} }
@ -319,7 +396,8 @@ void fk20_multi(void) {}
/** /**
* Initialise settings for an FK20 single proof. * Initialise settings for an FK20 single proof.
* *
* #free_fk20_single_settings must be called to deallocate this structure. * @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_fk20_single_settings.
* *
* @param[out] fk The initialised settings * @param[out] fk The initialised settings
* @param[in] n2 The desired size of `x_ext_fft`, a power of two * @param[in] n2 The desired size of `x_ext_fft`, a power of two
@ -340,15 +418,13 @@ C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZ
fk->ks = ks; fk->ks = ks;
fk->x_ext_fft_len = n2; fk->x_ext_fft_len = n2;
ASSERT(c_kzg_malloc((void **)&x, n * sizeof *x) == C_KZG_OK, C_KZG_MALLOC); TRY(c_kzg_malloc((void **)&x, n * sizeof *x));
ASSERT(c_kzg_malloc((void **)&fk->x_ext_fft, fk->x_ext_fft_len * sizeof *fk->x_ext_fft) == C_KZG_OK, C_KZG_MALLOC);
for (uint64_t i = 0; i < n - 1; i++) { for (uint64_t i = 0; i < n - 1; i++) {
x[i] = ks->secret_g1[n - 2 - i]; x[i] = ks->secret_g1[n - 2 - i];
} }
x[n - 1] = g1_identity; x[n - 1] = g1_identity;
ASSERT(toeplitz_part_1(fk->x_ext_fft, x, n, ks->fs) == C_KZG_OK, C_KZG_ERROR); TRY(new_toeplitz_part_1(&fk->x_ext_fft, x, n, ks->fs));
free(x); free(x);
return C_KZG_OK; return C_KZG_OK;
@ -357,10 +433,12 @@ C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZ
/** /**
* Initialise settings for an FK20 multi proof. * Initialise settings for an FK20 multi proof.
* *
* #free_fk20_single_settings must be called to deallocate this structure. * @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_fk20_multi_settings.
* *
* @param[out] fk The initialised settings * @param[out] fk The initialised settings
* @param[in] n2 The desired size of `x_ext_fft`, a power of two * @param[in] n2 The desired size of `x_ext_fft`, a power of two
* @param[in] chunk_len TODO
* @param[in] ks KZGSettings that have already been initialised * @param[in] ks KZGSettings that have already been initialised
* @retval C_CZK_OK All is well * @retval C_CZK_OK All is well
* @retval C_CZK_BADARGS Invalid parameters were supplied * @retval C_CZK_BADARGS Invalid parameters were supplied
@ -370,7 +448,6 @@ C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZ
C_KZG_RET new_fk20_multi_settings(FK20MultiSettings *fk, uint64_t n2, uint64_t chunk_len, const KZGSettings *ks) { C_KZG_RET new_fk20_multi_settings(FK20MultiSettings *fk, uint64_t n2, uint64_t chunk_len, const KZGSettings *ks) {
uint64_t n, k; uint64_t n, k;
blst_p1 *x; blst_p1 *x;
C_KZG_RET ret;
ASSERT(n2 <= ks->fs->max_width, C_KZG_BADARGS); ASSERT(n2 <= ks->fs->max_width, C_KZG_BADARGS);
ASSERT(is_power_of_two(n2), C_KZG_BADARGS); ASSERT(is_power_of_two(n2), C_KZG_BADARGS);
@ -385,11 +462,9 @@ C_KZG_RET new_fk20_multi_settings(FK20MultiSettings *fk, uint64_t n2, uint64_t c
fk->ks = ks; fk->ks = ks;
fk->chunk_len = chunk_len; fk->chunk_len = chunk_len;
ASSERT(c_kzg_malloc((void **)&fk->x_ext_fft_files, chunk_len * sizeof *fk->x_ext_fft_files) == C_KZG_OK, TRY(c_kzg_malloc((void **)&fk->x_ext_fft_files, chunk_len * sizeof *fk->x_ext_fft_files));
C_KZG_MALLOC);
// Temporary array TRY(c_kzg_malloc((void **)&x, k * sizeof *x));
ASSERT(c_kzg_malloc((void **)&x, k * sizeof *x) == C_KZG_OK, C_KZG_MALLOC);
for (uint64_t offset = 0; offset < chunk_len; offset++) { for (uint64_t offset = 0; offset < chunk_len; offset++) {
uint64_t start = n - chunk_len - 1 - offset; uint64_t start = n - chunk_len - 1 - offset;
for (uint64_t i = 0, j = start; i + 1 < k; i++, j -= chunk_len) { for (uint64_t i = 0, j = start; i + 1 < k; i++, j -= chunk_len) {
@ -397,12 +472,7 @@ C_KZG_RET new_fk20_multi_settings(FK20MultiSettings *fk, uint64_t n2, uint64_t c
} }
x[k - 1] = g1_identity; x[k - 1] = g1_identity;
ASSERT(c_kzg_malloc((void **)&fk->x_ext_fft_files[offset], 2 * k * sizeof *fk->x_ext_fft_files[offset]) == TRY(new_toeplitz_part_1(&fk->x_ext_fft_files[offset], x, k, ks->fs));
C_KZG_OK,
C_KZG_MALLOC);
ASSERT(ret = toeplitz_part_1(fk->x_ext_fft_files[offset], x, k, ks->fs) == C_KZG_OK,
ret == C_KZG_MALLOC ? ret : C_KZG_ERROR);
} }
free(x); free(x);
@ -415,7 +485,7 @@ C_KZG_RET new_fk20_multi_settings(FK20MultiSettings *fk, uint64_t n2, uint64_t c
* @param fk The settings to be freed * @param fk The settings to be freed
*/ */
void free_fk20_single_settings(FK20SingleSettings *fk) { void free_fk20_single_settings(FK20SingleSettings *fk) {
free(fk->x_ext_fft); free_toeplitz_part_1(fk->x_ext_fft);
fk->x_ext_fft_len = 0; fk->x_ext_fft_len = 0;
} }
@ -426,7 +496,7 @@ void free_fk20_single_settings(FK20SingleSettings *fk) {
*/ */
void free_fk20_multi_settings(FK20MultiSettings *fk) { void free_fk20_multi_settings(FK20MultiSettings *fk) {
for (uint64_t i = 0; i < fk->chunk_len; i++) { for (uint64_t i = 0; i < fk->chunk_len; i++) {
free((fk->x_ext_fft_files)[i]); free_toeplitz_part_1((fk->x_ext_fft_files)[i]);
} }
free(fk->x_ext_fft_files); free(fk->x_ext_fft_files);
fk->chunk_len = 0; fk->chunk_len = 0;

View File

@ -47,17 +47,17 @@
typedef struct { typedef struct {
const KZGSettings *ks; /**< The corresponding settings for performing KZG proofs */ const KZGSettings *ks; /**< The corresponding settings for performing KZG proofs */
blst_p1 *x_ext_fft; /**< The output of the first part of the Toeplitz process */ blst_p1 *x_ext_fft; /**< The output of the first part of the Toeplitz process */
uint64_t x_ext_fft_len; /**< The length of the `x_ext_fft_len` array */ uint64_t x_ext_fft_len; /**< The length of the `x_ext_fft_len` array (TODO - do we need this?)*/
} FK20SingleSettings; } FK20SingleSettings;
/** /**
* Stores the setup and parameters needed for computing FK20 multi proofs. * Stores the setup and parameters needed for computing FK20 multi proofs.
*/ */
typedef struct { typedef struct {
const KZGSettings *ks; /**< The corresponding settings for performing KZG proofs */ const KZGSettings *ks; /**< The corresponding settings for performing KZG proofs */
uint64_t chunk_len; uint64_t chunk_len; /**< TODO */
blst_p1 **x_ext_fft_files; blst_p1 **x_ext_fft_files; /**< TODO */
uint64_t length; uint64_t length; /**< TODO */
} FK20MultiSettings; } FK20MultiSettings;
int log2_pow2(uint32_t n); int log2_pow2(uint32_t n);
@ -65,9 +65,16 @@ uint32_t reverse_bits(uint32_t a);
uint32_t reverse_bits_limited(uint32_t n, uint32_t value); uint32_t reverse_bits_limited(uint32_t n, uint32_t value);
C_KZG_RET reverse_bit_order(void *values, size_t size, uint64_t n); C_KZG_RET reverse_bit_order(void *values, size_t size, uint64_t n);
C_KZG_RET toeplitz_part_1(blst_p1 *out, const blst_p1 *x, uint64_t n, const FFTSettings *fs); C_KZG_RET toeplitz_part_1(blst_p1 *out, const blst_p1 *x, uint64_t n, const FFTSettings *fs);
C_KZG_RET new_toeplitz_part_1(blst_p1 **out, const blst_p1 *x, uint64_t n, const FFTSettings *fs);
void free_toeplitz_part_1(blst_p1 *x);
C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20SingleSettings *fk); C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20SingleSettings *fk);
C_KZG_RET new_toeplitz_part_2(blst_p1 **out, const poly *toeplitz_coeffs, const FK20SingleSettings *fk);
void free_toeplitz_part_2(blst_p1 *x);
C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk); C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk);
C_KZG_RET new_toeplitz_part_3(blst_p1 **out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk);
void free_toeplitz_part_3(blst_p1 *x);
C_KZG_RET new_toeplitz_coeffs_step(poly *out, const poly *in); C_KZG_RET new_toeplitz_coeffs_step(poly *out, const poly *in);
void free_toeplitz_coeffs_step(poly *p);
C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, const FK20SingleSettings *fk); C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, const FK20SingleSettings *fk);
C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, const FK20SingleSettings *fk); C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, const FK20SingleSettings *fk);
C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZGSettings *ks); C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZGSettings *ks);

View File

@ -24,7 +24,6 @@
*/ */
#include <stddef.h> // NULL #include <stddef.h> // NULL
#include <stdlib.h> // free()
#include "kzg_proofs.h" #include "kzg_proofs.h"
#include "c_kzg_util.h" #include "c_kzg_util.h"
@ -104,7 +103,7 @@ C_KZG_RET compute_proof_multi(blst_p1 *out, const poly *p, const blst_fr *x0, ui
ASSERT(is_power_of_two(n), C_KZG_BADARGS); ASSERT(is_power_of_two(n), C_KZG_BADARGS);
// Construct x^n - x0^n = (x - w^0)(x - w^1)...(x - w^(n-1)) // Construct x^n - x0^n = (x - w^0)(x - w^1)...(x - w^(n-1))
ASSERT(new_poly(&divisor, n + 1) == C_KZG_OK, C_KZG_MALLOC); TRY(new_poly(&divisor, n + 1));
// -(x0^n) // -(x0^n)
fr_pow(&x_pow_n, x0, n); fr_pow(&x_pow_n, x0, n);
@ -119,7 +118,7 @@ C_KZG_RET compute_proof_multi(blst_p1 *out, const poly *p, const blst_fr *x0, ui
divisor.coeffs[n] = fr_one; divisor.coeffs[n] = fr_one;
// Calculate q = p / (x^n - x0^n) // Calculate q = p / (x^n - x0^n)
ASSERT(new_poly_long_div(&q, p, &divisor) == C_KZG_OK, C_KZG_ERROR); TRY(new_poly_long_div(&q, p, &divisor));
commit_to_poly(out, &q, ks); commit_to_poly(out, &q, ks);
@ -157,8 +156,8 @@ C_KZG_RET check_proof_multi(bool *out, const blst_p1 *commitment, const blst_p1
ASSERT(is_power_of_two(n), C_KZG_BADARGS); ASSERT(is_power_of_two(n), C_KZG_BADARGS);
// Interpolate at a coset. // Interpolate at a coset.
ASSERT(new_poly(&interp, n) == C_KZG_OK, C_KZG_MALLOC); TRY(new_poly(&interp, n));
ASSERT(fft_fr(interp.coeffs, ys, true, n, ks->fs) == C_KZG_OK, C_KZG_ERROR); TRY(fft_fr(interp.coeffs, ys, true, n, ks->fs));
// Because it is a coset, not the subgroup, we have to multiply the polynomial coefficients by x^-i // Because it is a coset, not the subgroup, we have to multiply the polynomial coefficients by x^-i
blst_fr_eucl_inverse(&inv_x, x); blst_fr_eucl_inverse(&inv_x, x);
@ -192,7 +191,8 @@ C_KZG_RET check_proof_multi(bool *out, const blst_p1 *commitment, const blst_p1
* *
* Space is allocated for the provided secrets (the "trusted setup"), and copies of the secrets are made. * Space is allocated for the provided secrets (the "trusted setup"), and copies of the secrets are made.
* *
* @remark This structure *must* be deallocated after use by calling #free_kzg_settings. * @remark As with all functions prefixed `new_`, this allocates memory that needs to be reclaimed by calling the
* corresponding `free_` function. In this case, #free_kzg_settings.
* *
* @param[out] ks The new settings * @param[out] ks The new settings
* @param[in] secret_g1 The G1 points from the trusted setup (an array of length at least @p length) * @param[in] secret_g1 The G1 points from the trusted setup (an array of length at least @p length)
@ -210,8 +210,8 @@ C_KZG_RET new_kzg_settings(KZGSettings *ks, const blst_p1 *secret_g1, const blst
ks->length = length; ks->length = length;
// Allocate space for the secrets // Allocate space for the secrets
ASSERT(c_kzg_malloc((void **)&ks->secret_g1, ks->length * sizeof *ks->secret_g1) == C_KZG_OK, C_KZG_MALLOC); TRY(c_kzg_malloc((void **)&ks->secret_g1, ks->length * sizeof *ks->secret_g1));
ASSERT(c_kzg_malloc((void **)&ks->secret_g2, ks->length * sizeof *ks->secret_g2) == C_KZG_OK, C_KZG_MALLOC); TRY(c_kzg_malloc((void **)&ks->secret_g2, ks->length * sizeof *ks->secret_g2));
// Populate the secrets // Populate the secrets
for (uint64_t i = 0; i < ks->length; i++) { for (uint64_t i = 0; i < ks->length; i++) {

View File

@ -20,7 +20,6 @@
* Operations on polynomials defined over the finite field. * Operations on polynomials defined over the finite field.
*/ */
#include <stdlib.h> // NULL, free()
#include "c_kzg_util.h" #include "c_kzg_util.h"
#include "poly.h" #include "poly.h"
@ -92,7 +91,7 @@ C_KZG_RET new_poly_long_div(poly *out, const poly *dividend, const poly *divisor
ASSERT(divisor->length > 0, C_KZG_BADARGS); ASSERT(divisor->length > 0, C_KZG_BADARGS);
// Initialise the output polynomial // Initialise the output polynomial
ASSERT(new_poly(out, poly_quotient_length(dividend, divisor)) == C_KZG_OK, C_KZG_MALLOC); TRY(new_poly(out, poly_quotient_length(dividend, divisor)));
// If the divisor is larger than the dividend, the result is zero-length // If the divisor is larger than the dividend, the result is zero-length
if (out->length == 0) return C_KZG_OK; if (out->length == 0) return C_KZG_OK;
@ -144,7 +143,7 @@ C_KZG_RET new_poly(poly *out, uint64_t length) {
* @retval C_CZK_MALLOC Memory allocation failed * @retval C_CZK_MALLOC Memory allocation failed
*/ */
C_KZG_RET new_poly_with_coeffs(poly *out, const blst_fr *coeffs, uint64_t length) { C_KZG_RET new_poly_with_coeffs(poly *out, const blst_fr *coeffs, uint64_t length) {
ASSERT(new_poly(out, length) == C_KZG_OK, C_KZG_MALLOC); TRY(new_poly(out, length));
for (uint64_t i = 0; i < length; i++) { for (uint64_t i = 0; i < length; i++) {
out->coeffs[i] = coeffs[i]; out->coeffs[i] = coeffs[i];
} }