Handle many missing (step 3)
This commit is contained in:
parent
8fbea3b3ef
commit
f09d1a70b2
128
src/zero_poly.c
128
src/zero_poly.c
|
@ -31,8 +31,8 @@
|
||||||
* Uses straightforward multiplication to calculate the product of `(x - r^i)` where `r` is a root of unity and the `i`s
|
* Uses straightforward multiplication to calculate the product of `(x - r^i)` where `r` is a root of unity and the `i`s
|
||||||
* are the indices at which it must evaluate to zero. This results in a polynomial of degree @p len_indices.
|
* are the indices at which it must evaluate to zero. This results in a polynomial of degree @p len_indices.
|
||||||
*
|
*
|
||||||
* @param[out] dst The resulting leaf, length @p len_dst
|
* @param[out] dst The resulting polynomial, length @p len_dst
|
||||||
* @param[in] len_dst Length of the output leaf, @p dst
|
* @param[in] len_dst Length of the output polynomial, @p dst
|
||||||
* @param[in] indices Array of missing indices of length @p len_indices
|
* @param[in] indices Array of missing indices of length @p len_indices
|
||||||
* @param[in] len_indices Length of the missing indices array, @p indices
|
* @param[in] len_indices Length of the missing indices array, @p indices
|
||||||
* @param[in] stride Stride length through the powers of the root of unity
|
* @param[in] stride Stride length through the powers of the root of unity
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
*
|
*
|
||||||
* @todo rework to pass polynomials in and out
|
* @todo rework to pass polynomials in and out
|
||||||
*/
|
*/
|
||||||
C_KZG_RET do_zero_poly_mul_leaf(fr_t *dst, uint64_t len_dst, const uint64_t *indices, uint64_t len_indices,
|
C_KZG_RET do_zero_poly_mul_partial(fr_t *dst, uint64_t len_dst, const uint64_t *indices, uint64_t len_indices,
|
||||||
uint64_t stride, const FFTSettings *fs) {
|
uint64_t stride, const FFTSettings *fs) {
|
||||||
|
|
||||||
CHECK(len_dst >= len_indices + 1);
|
CHECK(len_dst >= len_indices + 1);
|
||||||
|
@ -80,12 +80,12 @@ C_KZG_RET do_zero_poly_mul_leaf(fr_t *dst, uint64_t len_dst, const uint64_t *ind
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
C_KZG_RET pad_p(fr_t *out, uint64_t out_len, const fr_t *p, uint64_t p_len) {
|
C_KZG_RET pad_p(fr_t *out, uint64_t out_len, const poly *p) {
|
||||||
CHECK(out_len >= p_len);
|
CHECK(out_len >= p->length);
|
||||||
for (uint64_t i = 0; i < p_len; i++) {
|
for (uint64_t i = 0; i < p->length; i++) {
|
||||||
out[i] = p[i];
|
out[i] = p->coeffs[i];
|
||||||
}
|
}
|
||||||
for (uint64_t i = p_len; i < out_len; i++) {
|
for (uint64_t i = p->length; i < out_len; i++) {
|
||||||
out[i] = fr_zero;
|
out[i] = fr_zero;
|
||||||
}
|
}
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
|
@ -109,15 +109,15 @@ C_KZG_RET pad_p(fr_t *out, uint64_t out_len, const fr_t *p, uint64_t p_len) {
|
||||||
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
||||||
* @retval C_CZK_ERROR An internal error occurred
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
*/
|
*/
|
||||||
C_KZG_RET reduce_leaves(poly *out, uint64_t len_out, fr_t *scratch, uint64_t len_scratch, const poly *leaves,
|
C_KZG_RET reduce_partials(poly *out, uint64_t len_out, fr_t *scratch, uint64_t len_scratch, const poly *partials,
|
||||||
uint64_t leaf_count, const FFTSettings *fs) {
|
uint64_t partial_count, const FFTSettings *fs) {
|
||||||
CHECK(is_power_of_two(len_out));
|
CHECK(is_power_of_two(len_out));
|
||||||
CHECK(len_scratch >= 3 * len_out);
|
CHECK(len_scratch >= 3 * len_out);
|
||||||
CHECK(leaf_count > 0);
|
CHECK(partial_count > 0);
|
||||||
// The degree of the output polynomial is the sum of the degrees of the input polynomials.
|
// The degree of the output polynomial is the sum of the degrees of the input polynomials.
|
||||||
uint64_t out_degree = 0;
|
uint64_t out_degree = 0;
|
||||||
for (int i = 0; i < leaf_count; i++) {
|
for (int i = 0; i < partial_count; i++) {
|
||||||
out_degree += leaves[i].length - 1;
|
out_degree += partials[i].length - 1;
|
||||||
}
|
}
|
||||||
CHECK(out_degree + 1 <= len_out);
|
CHECK(out_degree + 1 <= len_out);
|
||||||
|
|
||||||
|
@ -126,12 +126,12 @@ C_KZG_RET reduce_leaves(poly *out, uint64_t len_out, fr_t *scratch, uint64_t len
|
||||||
fr_t *mul_eval_ps = scratch + len_out;
|
fr_t *mul_eval_ps = scratch + len_out;
|
||||||
fr_t *p_eval = scratch + 2 * len_out;
|
fr_t *p_eval = scratch + 2 * len_out;
|
||||||
|
|
||||||
// Do the last leaf first: it may be shorter than the others and the padding can remain in place for the rest.
|
// Do the last partial first: it may be shorter than the others and the padding can remain in place for the rest.
|
||||||
TRY(pad_p(p_padded, len_out, leaves[leaf_count - 1].coeffs, leaves[leaf_count - 1].length));
|
TRY(pad_p(p_padded, len_out, &partials[partial_count - 1]));
|
||||||
TRY(fft_fr(mul_eval_ps, p_padded, false, len_out, fs));
|
TRY(fft_fr(mul_eval_ps, p_padded, false, len_out, fs));
|
||||||
|
|
||||||
for (uint64_t i = 0; i < leaf_count - 1; i++) {
|
for (uint64_t i = 0; i < partial_count - 1; i++) {
|
||||||
TRY(pad_p(p_padded, leaves[i].length, leaves[i].coeffs, leaves[i].length));
|
TRY(pad_p(p_padded, partials[i].length, &partials[i]));
|
||||||
TRY(fft_fr(p_eval, p_padded, false, len_out, fs));
|
TRY(fft_fr(p_eval, p_padded, false, len_out, fs));
|
||||||
for (uint64_t j = 0; j < len_out; j++) {
|
for (uint64_t j = 0; j < len_out; j++) {
|
||||||
fr_mul(&mul_eval_ps[j], &mul_eval_ps[j], &p_eval[j]);
|
fr_mul(&mul_eval_ps[j], &mul_eval_ps[j], &p_eval[j]);
|
||||||
|
@ -149,7 +149,7 @@ C_KZG_RET reduce_leaves(poly *out, uint64_t len_out, fr_t *scratch, uint64_t len
|
||||||
* indices.
|
* indices.
|
||||||
*
|
*
|
||||||
* This is done by simply multiplying together `(x - r^i)` for all the `i` that are missing indices, using a combination
|
* This is done by simply multiplying together `(x - r^i)` for all the `i` that are missing indices, using a combination
|
||||||
* of direct multiplication (#do_zero_poly_mul_leaf) and multiplication via convolution (#reduce_leaves).
|
* of direct multiplication (#do_zero_poly_mul_partial) and multiplication via convolution (#reduce_partials).
|
||||||
*
|
*
|
||||||
* Also calculates the FFT (the "evaluation polynomial").
|
* Also calculates the FFT (the "evaluation polynomial").
|
||||||
*
|
*
|
||||||
|
@ -172,7 +172,7 @@ C_KZG_RET reduce_leaves(poly *out, uint64_t len_out, fr_t *scratch, uint64_t len
|
||||||
* @retval C_CZK_ERROR An internal error occurred
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
* @retval C_CZK_MALLOC Memory allocation failed
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
*
|
*
|
||||||
* @todo What is the performance impact of tuning `per_leaf_poly` and `reduction factor`?
|
* @todo What is the performance impact of tuning `degree_of_partial` and `reduction factor`?
|
||||||
*/
|
*/
|
||||||
C_KZG_RET zero_polynomial_via_multiplication(fr_t *zero_eval, fr_t *zero_poly, uint64_t *zero_poly_len, uint64_t length,
|
C_KZG_RET zero_polynomial_via_multiplication(fr_t *zero_eval, fr_t *zero_poly, uint64_t *zero_poly_len, uint64_t length,
|
||||||
const uint64_t *missing_indices, uint64_t len_missing,
|
const uint64_t *missing_indices, uint64_t len_missing,
|
||||||
|
@ -189,83 +189,81 @@ C_KZG_RET zero_polynomial_via_multiplication(fr_t *zero_eval, fr_t *zero_poly, u
|
||||||
CHECK(length <= fs->max_width);
|
CHECK(length <= fs->max_width);
|
||||||
CHECK(is_power_of_two(length));
|
CHECK(is_power_of_two(length));
|
||||||
|
|
||||||
uint64_t per_leaf_poly = 64; // Tunable parameter. Must be a power of two.
|
uint64_t degree_of_partial = 64; // Tunable parameter. Must be a power of two.
|
||||||
uint64_t per_leaf = per_leaf_poly - 1;
|
uint64_t missing_per_partial = degree_of_partial - 1;
|
||||||
uint64_t domain_stride = fs->max_width / length;
|
uint64_t domain_stride = fs->max_width / length;
|
||||||
uint64_t leaf_count = (len_missing + per_leaf - 1) / per_leaf;
|
uint64_t partial_count = (len_missing + missing_per_partial - 1) / missing_per_partial;
|
||||||
uint64_t n = next_power_of_two(leaf_count * per_leaf_poly);
|
uint64_t n = next_power_of_two(partial_count * degree_of_partial);
|
||||||
if (n > length) n = length;
|
if (n > length) n = length;
|
||||||
|
|
||||||
if (len_missing <= per_leaf) {
|
if (len_missing <= missing_per_partial) {
|
||||||
TRY(do_zero_poly_mul_leaf(zero_poly, length, missing_indices, len_missing, domain_stride, fs));
|
TRY(do_zero_poly_mul_partial(zero_poly, length, missing_indices, len_missing, domain_stride, fs));
|
||||||
TRY(fft_fr(zero_eval, zero_poly, false, length, fs));
|
TRY(fft_fr(zero_eval, zero_poly, false, length, fs));
|
||||||
*zero_poly_len = len_missing + 1;
|
*zero_poly_len = len_missing + 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Work space for building and reducing the leaves
|
// Work space for building and reducing the partials
|
||||||
fr_t *work;
|
fr_t *work;
|
||||||
TRY(new_fr_array(&work, next_power_of_two(leaf_count * per_leaf_poly)));
|
TRY(new_fr_array(&work, next_power_of_two(partial_count * degree_of_partial)));
|
||||||
|
|
||||||
// Build the leaves.
|
// Build the partials.
|
||||||
|
|
||||||
// Just allocate pointers here since we're re-using `work` for the leaf processing
|
// Just allocate pointers here since we're re-using `work` for the partial processing
|
||||||
// Combining leaves can be done mostly in-place, using a scratchpad.
|
// Combining partials can be done mostly in-place, using a scratchpad.
|
||||||
poly *leaves;
|
poly *partials;
|
||||||
TRY(new_poly_array(&leaves, leaf_count));
|
TRY(new_poly_array(&partials, partial_count));
|
||||||
uint64_t offset = 0, out_offset = 0, max = len_missing;
|
uint64_t offset = 0, out_offset = 0, max = len_missing;
|
||||||
for (int i = 0; i < leaf_count; i++) {
|
for (int i = 0; i < partial_count; i++) {
|
||||||
uint64_t end = offset + per_leaf;
|
uint64_t end = offset + missing_per_partial;
|
||||||
if (end > max) end = max;
|
if (end > max) end = max;
|
||||||
leaves[i].coeffs = &work[out_offset];
|
partials[i].coeffs = &work[out_offset];
|
||||||
leaves[i].length = per_leaf_poly;
|
partials[i].length = degree_of_partial;
|
||||||
TRY(do_zero_poly_mul_leaf(leaves[i].coeffs, per_leaf_poly, &missing_indices[offset], end - offset,
|
TRY(do_zero_poly_mul_partial(partials[i].coeffs, degree_of_partial, &missing_indices[offset], end - offset,
|
||||||
domain_stride, fs));
|
domain_stride, fs));
|
||||||
offset += per_leaf;
|
offset += missing_per_partial;
|
||||||
out_offset += per_leaf_poly;
|
out_offset += degree_of_partial;
|
||||||
}
|
}
|
||||||
// Adjust the length of the last leaf
|
// Adjust the length of the last partial
|
||||||
// leaf_lengths[leaf_count - 1] = 1 + len_missing % per_leaf;
|
partials[partial_count - 1].length = 1 + len_missing - (partial_count - 1) * missing_per_partial;
|
||||||
leaves[leaf_count - 1].length = 1 + len_missing - (leaf_count - 1) * per_leaf;
|
|
||||||
|
|
||||||
// Now reduce all the leaves to a single poly
|
// Reduce all the partials to a single poly
|
||||||
|
|
||||||
int reduction_factor = 4; // must be a power of 2 (TODO why?)
|
int reduction_factor = 4; // must be a power of 2 (for sake of the FFTs in reduce partials)
|
||||||
fr_t *scratch;
|
fr_t *scratch;
|
||||||
TRY(new_fr_array(&scratch, n * 3));
|
TRY(new_fr_array(&scratch, n * 3));
|
||||||
while (leaf_count > 1) {
|
while (partial_count > 1) {
|
||||||
uint64_t reduced_count = (leaf_count + reduction_factor - 1) / reduction_factor;
|
uint64_t reduced_count = (partial_count + reduction_factor - 1) / reduction_factor;
|
||||||
uint64_t leaf_size = next_power_of_two(leaves[0].length);
|
uint64_t partial_size = next_power_of_two(partials[0].length);
|
||||||
for (uint64_t i = 0; i < reduced_count; i++) {
|
for (uint64_t i = 0; i < reduced_count; i++) {
|
||||||
uint64_t start = i * reduction_factor;
|
uint64_t start = i * reduction_factor;
|
||||||
uint64_t end = start + reduction_factor;
|
uint64_t end = start + reduction_factor;
|
||||||
// E.g. if we *started* with 2 leaves, we won't have more than that since it is already a power
|
uint64_t out_end = end * partial_size;
|
||||||
// of 2. If we had 3, it would have been rounded up anyway. So just pick the end
|
|
||||||
uint64_t out_end = end * leaf_size;
|
|
||||||
if (out_end > n) out_end = n;
|
if (out_end > n) out_end = n;
|
||||||
fr_t *reduced = work + start * leaf_size;
|
fr_t *reduced = work + start * partial_size;
|
||||||
uint64_t reduced_len = out_end - start * leaf_size;
|
uint64_t reduced_len = out_end - start * partial_size;
|
||||||
if (reduced_len > length) reduced_len = length;
|
if (reduced_len > length) reduced_len = length;
|
||||||
if (end > leaf_count) end = leaf_count;
|
if (end > partial_count) end = partial_count;
|
||||||
uint64_t leaves_slice_len = end - start;
|
uint64_t partials_slice = end - start;
|
||||||
if (leaves_slice_len > 1) {
|
partials[i].coeffs = reduced;
|
||||||
leaves[i].coeffs = reduced;
|
if (partials_slice > 1) {
|
||||||
TRY(reduce_leaves(&leaves[i], reduced_len, scratch, n * 3, &leaves[start], leaves_slice_len, fs));
|
TRY(reduce_partials(&partials[i], reduced_len, scratch, n * 3, &partials[start], partials_slice,
|
||||||
|
fs));
|
||||||
} else {
|
} else {
|
||||||
leaves[i].coeffs = reduced;
|
partials[i].length = partials[start].length;
|
||||||
leaves[i].length = leaves[start].length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
leaf_count = reduced_count;
|
partial_count = reduced_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
*zero_poly_len = leaves[0].length;
|
// Process final output
|
||||||
for (uint64_t i = 0; i < length; i++) {
|
|
||||||
zero_poly[i] = i < *zero_poly_len ? leaves[0].coeffs[i] : fr_zero;
|
TRY(pad_p(zero_poly, length, &partials[0]));
|
||||||
}
|
|
||||||
TRY(fft_fr(zero_eval, zero_poly, false, length, fs));
|
TRY(fft_fr(zero_eval, zero_poly, false, length, fs));
|
||||||
|
|
||||||
|
*zero_poly_len = partials[0].length;
|
||||||
|
|
||||||
free(work);
|
free(work);
|
||||||
free(leaves);
|
free(partials);
|
||||||
free(scratch);
|
free(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,17 @@
|
||||||
/**
|
/**
|
||||||
* @file zero_poly.h
|
* @file zero_poly.h
|
||||||
*
|
*
|
||||||
* Methods for constructing zero polynomials and reconstructing polynomials from partial evaluations on a subgroup
|
* Methods for constructing polynomials that evaluate to zero for given lists of powers of roots of unity.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "c_kzg.h"
|
#include "c_kzg.h"
|
||||||
#include "fft_common.h"
|
#include "fft_common.h"
|
||||||
#include "poly.h"
|
#include "poly.h"
|
||||||
|
|
||||||
C_KZG_RET do_zero_poly_mul_leaf(fr_t *dst, uint64_t len_dst, const uint64_t *indices, uint64_t len_indices,
|
C_KZG_RET do_zero_poly_mul_partial(fr_t *dst, uint64_t len_dst, const uint64_t *indices, uint64_t len_indices,
|
||||||
uint64_t stride, const FFTSettings *fs);
|
uint64_t stride, const FFTSettings *fs);
|
||||||
C_KZG_RET reduce_leaves(poly *dst, uint64_t len_dst, fr_t *scratch, uint64_t len_scratch, const poly *leaves,
|
C_KZG_RET reduce_partials(poly *dst, uint64_t len_dst, fr_t *scratch, uint64_t len_scratch, const poly *partials,
|
||||||
uint64_t leaf_count, const FFTSettings *fs);
|
uint64_t partial_count, const FFTSettings *fs);
|
||||||
C_KZG_RET zero_polynomial_via_multiplication(fr_t *zero_eval, fr_t *zero_poly, uint64_t *zero_poly_len, uint64_t length,
|
C_KZG_RET zero_polynomial_via_multiplication(fr_t *zero_eval, fr_t *zero_poly, uint64_t *zero_poly_len, uint64_t length,
|
||||||
const uint64_t *missing_indices, uint64_t len_missing,
|
const uint64_t *missing_indices, uint64_t len_missing,
|
||||||
const FFTSettings *fs);
|
const FFTSettings *fs);
|
||||||
|
|
|
@ -60,30 +60,30 @@ uint64_t expected_poly_u64[16][4] = {
|
||||||
{0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L},
|
{0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L},
|
||||||
{0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L}};
|
{0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L}};
|
||||||
|
|
||||||
void test_reduce_leaves(void) {
|
void test_reduce_partials(void) {
|
||||||
FFTSettings fs;
|
FFTSettings fs;
|
||||||
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, 4));
|
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, 4));
|
||||||
fr_t from_tree_reduction_coeffs[16], from_direct[9], scratch[48];
|
fr_t from_tree_reduction_coeffs[16], from_direct[9], scratch[48];
|
||||||
poly from_tree_reduction;
|
poly from_tree_reduction;
|
||||||
from_tree_reduction.coeffs = from_tree_reduction_coeffs;
|
from_tree_reduction.coeffs = from_tree_reduction_coeffs;
|
||||||
|
|
||||||
// Via reduce_leaves
|
// Via reduce_partials
|
||||||
|
|
||||||
poly leaves[4];
|
poly partials[4];
|
||||||
fr_t leaf0[3], leaf1[3], leaf2[3], leaf3[3];
|
fr_t partial0[3], partial1[3], partial2[3], partial3[3];
|
||||||
leaves[0].coeffs = leaf0, leaves[0].length = 3;
|
partials[0].coeffs = partial0, partials[0].length = 3;
|
||||||
leaves[1].coeffs = leaf1, leaves[1].length = 3;
|
partials[1].coeffs = partial1, partials[1].length = 3;
|
||||||
leaves[2].coeffs = leaf2, leaves[2].length = 3;
|
partials[2].coeffs = partial2, partials[2].length = 3;
|
||||||
leaves[3].coeffs = leaf3, leaves[3].length = 3;
|
partials[3].coeffs = partial3, partials[3].length = 3;
|
||||||
const uint64_t leaf_indices[4][2] = {{1, 3}, {7, 8}, {9, 10}, {12, 13}};
|
const uint64_t partial_indices[4][2] = {{1, 3}, {7, 8}, {9, 10}, {12, 13}};
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
TEST_CHECK(C_KZG_OK == do_zero_poly_mul_leaf(leaves[i].coeffs, 3, leaf_indices[i], 2, 1, &fs));
|
TEST_CHECK(C_KZG_OK == do_zero_poly_mul_partial(partials[i].coeffs, 3, partial_indices[i], 2, 1, &fs));
|
||||||
}
|
}
|
||||||
TEST_CHECK(C_KZG_OK == reduce_leaves(&from_tree_reduction, 16, scratch, 48, leaves, 4, &fs));
|
TEST_CHECK(C_KZG_OK == reduce_partials(&from_tree_reduction, 16, scratch, 48, partials, 4, &fs));
|
||||||
|
|
||||||
// Direct
|
// Direct
|
||||||
uint64_t indices[] = {1, 3, 7, 8, 9, 10, 12, 13};
|
uint64_t indices[] = {1, 3, 7, 8, 9, 10, 12, 13};
|
||||||
TEST_CHECK(C_KZG_OK == do_zero_poly_mul_leaf(from_direct, 9, indices, 8, 1, &fs));
|
TEST_CHECK(C_KZG_OK == do_zero_poly_mul_partial(from_direct, 9, indices, 8, 1, &fs));
|
||||||
|
|
||||||
// Compare
|
// Compare
|
||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
|
@ -93,7 +93,7 @@ void test_reduce_leaves(void) {
|
||||||
free_fft_settings(&fs);
|
free_fft_settings(&fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reduce_leaves_random(void) {
|
void reduce_partials_random(void) {
|
||||||
for (int scale = 5; scale < 13; scale++) {
|
for (int scale = 5; scale < 13; scale++) {
|
||||||
for (int ii = 1; ii <= 7; ii++) {
|
for (int ii = 1; ii <= 7; ii++) {
|
||||||
float missing_ratio = 0.1 * ii;
|
float missing_ratio = 0.1 * ii;
|
||||||
|
@ -110,24 +110,24 @@ void reduce_leaves_random(void) {
|
||||||
}
|
}
|
||||||
shuffle(missing, point_count);
|
shuffle(missing, point_count);
|
||||||
|
|
||||||
// Build the leaves
|
// Build the partials
|
||||||
poly *leaves;
|
poly *partials;
|
||||||
const int points_per_leaf = 63;
|
const int missing_per_partial = 63;
|
||||||
uint64_t indices[points_per_leaf];
|
uint64_t indices[missing_per_partial];
|
||||||
uint64_t leaf_count = (missing_count + points_per_leaf - 1) / points_per_leaf;
|
uint64_t partial_count = (missing_count + missing_per_partial - 1) / missing_per_partial;
|
||||||
TEST_CHECK(C_KZG_OK == new_poly_array(&leaves, leaf_count));
|
TEST_CHECK(C_KZG_OK == new_poly_array(&partials, partial_count));
|
||||||
for (uint64_t i = 0; i < leaf_count; i++) {
|
for (uint64_t i = 0; i < partial_count; i++) {
|
||||||
uint64_t start = i * points_per_leaf;
|
uint64_t start = i * missing_per_partial;
|
||||||
uint64_t end = start + points_per_leaf;
|
uint64_t end = start + missing_per_partial;
|
||||||
if (end > missing_count) end = missing_count;
|
if (end > missing_count) end = missing_count;
|
||||||
uint64_t leaf_size = end - start;
|
uint64_t partial_size = end - start;
|
||||||
TEST_CHECK(C_KZG_OK == new_fr_array(&leaves[i].coeffs, leaf_size + 1));
|
TEST_CHECK(C_KZG_OK == new_fr_array(&partials[i].coeffs, partial_size + 1));
|
||||||
for (int j = 0; j < leaf_size; j++) {
|
for (int j = 0; j < partial_size; j++) {
|
||||||
indices[j] = missing[i * points_per_leaf + j];
|
indices[j] = missing[i * missing_per_partial + j];
|
||||||
}
|
}
|
||||||
leaves[i].length = leaf_size + 1;
|
partials[i].length = partial_size + 1;
|
||||||
TEST_CHECK(C_KZG_OK ==
|
TEST_CHECK(C_KZG_OK == do_zero_poly_mul_partial(partials[i].coeffs, partials[i].length, indices,
|
||||||
do_zero_poly_mul_leaf(leaves[i].coeffs, leaves[i].length, indices, leaf_size, 1, &fs));
|
partial_size, 1, &fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
// From tree reduction
|
// From tree reduction
|
||||||
|
@ -135,13 +135,13 @@ void reduce_leaves_random(void) {
|
||||||
TEST_CHECK(C_KZG_OK == new_poly(&from_tree_reduction, point_count));
|
TEST_CHECK(C_KZG_OK == new_poly(&from_tree_reduction, point_count));
|
||||||
fr_t *scratch;
|
fr_t *scratch;
|
||||||
TEST_CHECK(C_KZG_OK == new_fr_array(&scratch, point_count * 3));
|
TEST_CHECK(C_KZG_OK == new_fr_array(&scratch, point_count * 3));
|
||||||
TEST_CHECK(C_KZG_OK == reduce_leaves(&from_tree_reduction, point_count, scratch, point_count * 3, leaves,
|
TEST_CHECK(C_KZG_OK == reduce_partials(&from_tree_reduction, point_count, scratch, point_count * 3,
|
||||||
leaf_count, &fs));
|
partials, partial_count, &fs));
|
||||||
|
|
||||||
// From direct
|
// From direct
|
||||||
fr_t *from_direct;
|
fr_t *from_direct;
|
||||||
TEST_CHECK(C_KZG_OK == new_fr_array(&from_direct, missing_count + 1));
|
TEST_CHECK(C_KZG_OK == new_fr_array(&from_direct, missing_count + 1));
|
||||||
TEST_CHECK(C_KZG_OK == do_zero_poly_mul_leaf(from_direct, missing_count + 1, missing, missing_count,
|
TEST_CHECK(C_KZG_OK == do_zero_poly_mul_partial(from_direct, missing_count + 1, missing, missing_count,
|
||||||
fs.max_width / point_count, &fs));
|
fs.max_width / point_count, &fs));
|
||||||
|
|
||||||
for (uint64_t i = 0; i < missing_count + 1; i++) {
|
for (uint64_t i = 0; i < missing_count + 1; i++) {
|
||||||
|
@ -151,10 +151,10 @@ void reduce_leaves_random(void) {
|
||||||
free_poly(&from_tree_reduction);
|
free_poly(&from_tree_reduction);
|
||||||
free(from_direct);
|
free(from_direct);
|
||||||
free(scratch);
|
free(scratch);
|
||||||
for (uint64_t i = 0; i < leaf_count; i++) {
|
for (uint64_t i = 0; i < partial_count; i++) {
|
||||||
free_poly(&leaves[i]);
|
free_poly(&partials[i]);
|
||||||
}
|
}
|
||||||
free(leaves);
|
free(partials);
|
||||||
free(missing);
|
free(missing);
|
||||||
free_fft_settings(&fs);
|
free_fft_settings(&fs);
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ void zero_poly_random(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix up the edge cases - zero_poly... fails for very large numbers of missing indices
|
// We know it doesn't work when all indices are missing
|
||||||
if (len_missing == fs.max_width) {
|
if (len_missing == fs.max_width) {
|
||||||
free_fft_settings(&fs);
|
free_fft_settings(&fs);
|
||||||
continue;
|
continue;
|
||||||
|
@ -284,8 +284,6 @@ void zero_poly_random(void) {
|
||||||
fr_t out;
|
fr_t out;
|
||||||
eval_poly(&out, &p, &fs.expanded_roots_of_unity[missing[i]]);
|
eval_poly(&out, &p, &fs.expanded_roots_of_unity[missing[i]]);
|
||||||
ret = TEST_CHECK(fr_is_zero(&out));
|
ret = TEST_CHECK(fr_is_zero(&out));
|
||||||
TEST_MSG("Failed for scale = %d, len_missing = %d, zero_poly_len = %lu", scale, len_missing,
|
|
||||||
zero_poly_len);
|
|
||||||
TEST_MSG("Failed for missing[%d] = %lu", i, missing[i]);
|
TEST_MSG("Failed for missing[%d] = %lu", i, missing[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,6 +326,9 @@ void zero_poly_all_but_one(void) {
|
||||||
TEST_CHECK(C_KZG_OK == zero_polynomial_via_multiplication(zero_eval, zero_poly, &zero_poly_len, fs.max_width,
|
TEST_CHECK(C_KZG_OK == zero_polynomial_via_multiplication(zero_eval, zero_poly, &zero_poly_len, fs.max_width,
|
||||||
missing, len_missing, &fs));
|
missing, len_missing, &fs));
|
||||||
|
|
||||||
|
TEST_CHECK(len_missing + 1 == zero_poly_len);
|
||||||
|
TEST_MSG("ZeroPolyLen: expected %d, got %lu", len_missing + 1, zero_poly_len);
|
||||||
|
|
||||||
poly p;
|
poly p;
|
||||||
p.length = zero_poly_len;
|
p.length = zero_poly_len;
|
||||||
p.coeffs = zero_poly;
|
p.coeffs = zero_poly;
|
||||||
|
@ -376,7 +377,7 @@ void zero_poly_252(void) {
|
||||||
TEST_CHECK(C_KZG_OK == zero_polynomial_via_multiplication(zero_eval, zero_poly, &zero_poly_len, fs.max_width,
|
TEST_CHECK(C_KZG_OK == zero_polynomial_via_multiplication(zero_eval, zero_poly, &zero_poly_len, fs.max_width,
|
||||||
missing, len_missing, &fs));
|
missing, len_missing, &fs));
|
||||||
|
|
||||||
TEST_CHECK(253 == zero_poly_len);
|
TEST_CHECK(len_missing + 1 == zero_poly_len);
|
||||||
TEST_MSG("ZeroPolyLen: expected %d, got %lu", len_missing + 1, zero_poly_len);
|
TEST_MSG("ZeroPolyLen: expected %d, got %lu", len_missing + 1, zero_poly_len);
|
||||||
|
|
||||||
poly p;
|
poly p;
|
||||||
|
@ -409,9 +410,9 @@ void zero_poly_252(void) {
|
||||||
|
|
||||||
TEST_LIST = {
|
TEST_LIST = {
|
||||||
{"ZERO_POLY_TEST", title},
|
{"ZERO_POLY_TEST", title},
|
||||||
{"test_reduce_leaves", test_reduce_leaves},
|
{"test_reduce_partials", test_reduce_partials},
|
||||||
{"check_test_data", check_test_data},
|
{"check_test_data", check_test_data},
|
||||||
{"reduce_leaves_random", reduce_leaves_random},
|
{"reduce_partials_random", reduce_partials_random},
|
||||||
{"zero_poly_known", zero_poly_known},
|
{"zero_poly_known", zero_poly_known},
|
||||||
{"zero_poly_random", zero_poly_random},
|
{"zero_poly_random", zero_poly_random},
|
||||||
{"zero_poly_all_but_one", zero_poly_all_but_one},
|
{"zero_poly_all_but_one", zero_poly_all_but_one},
|
||||||
|
|
Loading…
Reference in New Issue