Implement recovery from samples
This commit is contained in:
parent
345a16bf8a
commit
2c22bb9dae
|
@ -1,7 +1,7 @@
|
||||||
TESTS = bls12_381_test das_extension_test c_kzg_util_test fft_common_test fft_fr_test fft_g1_test \
|
TESTS = bls12_381_test das_extension_test c_kzg_util_test fft_common_test fft_fr_test fft_g1_test \
|
||||||
fk20_proofs_test kzg_proofs_test poly_test utility_test zero_poly_test
|
fk20_proofs_test kzg_proofs_test poly_test recover_test utility_test zero_poly_test
|
||||||
BENCH = fft_fr_bench fft_g1_bench
|
BENCH = fft_fr_bench fft_g1_bench
|
||||||
LIB_SRC = bls12_381.c c_kzg_util.c das_extension.c fft_common.c fft_fr.c fft_g1.c fk20_proofs.c kzg_proofs.c poly.c utility.c zero_poly.c
|
LIB_SRC = bls12_381.c c_kzg_util.c das_extension.c fft_common.c fft_fr.c fft_g1.c fk20_proofs.c kzg_proofs.c poly.c recover.c utility.c zero_poly.c
|
||||||
LIB_OBJ = $(LIB_SRC:.c=.o)
|
LIB_OBJ = $(LIB_SRC:.c=.o)
|
||||||
|
|
||||||
CFLAGS =
|
CFLAGS =
|
||||||
|
|
|
@ -44,7 +44,7 @@ int log_2_byte(byte b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the operand is zero in the finite field.
|
* Test whether the operand is zero in the finite field.
|
||||||
*
|
*
|
||||||
* @param p The field element to be checked
|
* @param p The field element to be checked
|
||||||
* @retval true The element is zero
|
* @retval true The element is zero
|
||||||
|
@ -59,7 +59,7 @@ bool fr_is_zero(const fr_t *p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the operand is one in the finite field.
|
* Test whether the operand is one in the finite field.
|
||||||
*
|
*
|
||||||
* @param p The field element to be checked
|
* @param p The field element to be checked
|
||||||
* @retval true The element is one
|
* @retval true The element is one
|
||||||
|
@ -73,6 +73,19 @@ bool fr_is_one(const fr_t *p) {
|
||||||
return a[0] == 1 && a[1] == 0 && a[2] == 0 && a[3] == 0;
|
return a[0] == 1 && a[1] == 0 && a[2] == 0 && a[3] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the operand is a specially defined NULL value.
|
||||||
|
*
|
||||||
|
* @param p The field element to be checked
|
||||||
|
* @retval true The element is the NULL value
|
||||||
|
* @retval false The element is not the NULL value
|
||||||
|
*/
|
||||||
|
bool fr_is_null(const fr_t *p) {
|
||||||
|
uint64_t *null = (uint64_t *)&fr_null;
|
||||||
|
uint64_t *a = (uint64_t *)p;
|
||||||
|
return a[0] == null[0] && a[1] == null[1] && a[2] == null[2] && a[3] == null[3];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a field element from a scalar, which is a little-endian sequence of bytes.
|
* Create a field element from a scalar, which is a little-endian sequence of bytes.
|
||||||
*
|
*
|
||||||
|
@ -182,8 +195,9 @@ void fr_inv(fr_t *out, const fr_t *a) {
|
||||||
* @param[in] b The divisor
|
* @param[in] b The divisor
|
||||||
*/
|
*/
|
||||||
void fr_div(fr_t *out, const fr_t *a, const fr_t *b) {
|
void fr_div(fr_t *out, const fr_t *a, const fr_t *b) {
|
||||||
blst_fr_eucl_inverse(out, b);
|
blst_fr tmp;
|
||||||
blst_fr_mul(out, out, a);
|
blst_fr_eucl_inverse(&tmp, b);
|
||||||
|
blst_fr_mul(out, a, &tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -48,6 +48,9 @@ static const fr_t fr_zero = {0L, 0L, 0L, 0L};
|
||||||
// This is 1 in Blst's `blst_fr` limb representation. Crazy but true.
|
// This is 1 in Blst's `blst_fr` limb representation. Crazy but true.
|
||||||
static const fr_t fr_one = {0x00000001fffffffeL, 0x5884b7fa00034802L, 0x998c4fefecbc4ff5L, 0x1824b159acc5056fL};
|
static const fr_t fr_one = {0x00000001fffffffeL, 0x5884b7fa00034802L, 0x998c4fefecbc4ff5L, 0x1824b159acc5056fL};
|
||||||
|
|
||||||
|
// Define a NULL value for fr_t. TODO - does this make sense?
|
||||||
|
static const fr_t fr_null = {0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL};
|
||||||
|
|
||||||
// The G1 identity/infinity
|
// The G1 identity/infinity
|
||||||
static const g1_t g1_identity = {{0L, 0L, 0L, 0L, 0L, 0L}, {0L, 0L, 0L, 0L, 0L, 0L}, {0L, 0L, 0L, 0L, 0L, 0L}};
|
static const g1_t g1_identity = {{0L, 0L, 0L, 0L, 0L, 0L}, {0L, 0L, 0L, 0L, 0L, 0L}, {0L, 0L, 0L, 0L, 0L, 0L}};
|
||||||
|
|
||||||
|
@ -97,6 +100,7 @@ static const g2_t g2_negative_generator = {{{{0xf5f28fa202940a10L, 0xb3f5fb2687b
|
||||||
int log_2_byte(byte b);
|
int log_2_byte(byte b);
|
||||||
bool fr_is_zero(const fr_t *p);
|
bool fr_is_zero(const fr_t *p);
|
||||||
bool fr_is_one(const fr_t *p);
|
bool fr_is_one(const fr_t *p);
|
||||||
|
bool fr_is_null(const fr_t *p);
|
||||||
void fr_from_scalar(fr_t *out, const scalar_t *a);
|
void fr_from_scalar(fr_t *out, const scalar_t *a);
|
||||||
void fr_from_uint64s(fr_t *out, const uint64_t *vals);
|
void fr_from_uint64s(fr_t *out, const uint64_t *vals);
|
||||||
void fr_from_uint64(fr_t *out, uint64_t n);
|
void fr_from_uint64(fr_t *out, uint64_t n);
|
||||||
|
|
|
@ -38,6 +38,12 @@ void fr_is_one_works(void) {
|
||||||
TEST_CHECK(fr_is_one(&fr_one));
|
TEST_CHECK(fr_is_one(&fr_one));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fr_is_null_works(void) {
|
||||||
|
TEST_CHECK(fr_is_null(&fr_null));
|
||||||
|
TEST_CHECK(!fr_is_null(&fr_zero));
|
||||||
|
TEST_CHECK(!fr_is_null(&fr_one));
|
||||||
|
}
|
||||||
|
|
||||||
void fr_from_uint64_works(void) {
|
void fr_from_uint64_works(void) {
|
||||||
fr_t a;
|
fr_t a;
|
||||||
fr_from_uint64(&a, 1);
|
fr_from_uint64(&a, 1);
|
||||||
|
@ -187,6 +193,7 @@ TEST_LIST = {
|
||||||
{"log_2_byte_works", log_2_byte_works},
|
{"log_2_byte_works", log_2_byte_works},
|
||||||
{"fr_is_zero_works", fr_is_zero_works},
|
{"fr_is_zero_works", fr_is_zero_works},
|
||||||
{"fr_is_one_works", fr_is_one_works},
|
{"fr_is_one_works", fr_is_one_works},
|
||||||
|
{"fr_is_null_works", fr_is_null_works},
|
||||||
{"fr_from_uint64_works", fr_from_uint64_works},
|
{"fr_from_uint64_works", fr_from_uint64_works},
|
||||||
{"fr_equal_works", fr_equal_works},
|
{"fr_equal_works", fr_equal_works},
|
||||||
{"fr_negate_works", fr_negate_works},
|
{"fr_negate_works", fr_negate_works},
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Benjamin Edgington
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file recover.c
|
||||||
|
*
|
||||||
|
* Recover polynomials from samples.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "recover.h"
|
||||||
|
#include "c_kzg_util.h"
|
||||||
|
#include "fft_fr.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "zero_poly.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shift a polynomial in place.
|
||||||
|
*
|
||||||
|
* Multiplies each coefficient by 1 / shift_factor ^ i.
|
||||||
|
*
|
||||||
|
* @param[out,in] p The polynomial coefficients to be shifted
|
||||||
|
* @param[in] len_p Length of the polynomial coefficients
|
||||||
|
*/
|
||||||
|
void shift_poly(fr_t *p, uint64_t len_p) {
|
||||||
|
fr_t shift_factor, factor_power, inv_factor;
|
||||||
|
fr_from_uint64(&shift_factor, 5); // primitive root of unity
|
||||||
|
fr_inv(&inv_factor, &shift_factor);
|
||||||
|
factor_power = fr_one;
|
||||||
|
|
||||||
|
for (uint64_t i = 1; i < len_p; i++) {
|
||||||
|
fr_mul(&factor_power, &factor_power, &inv_factor);
|
||||||
|
fr_mul(&p[i], &p[i], &factor_power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unshift a polynomial in place.
|
||||||
|
*
|
||||||
|
* Multiplies each coefficient by shift_factor ^ i.
|
||||||
|
*
|
||||||
|
* @param[out,in] p The polynomial coefficients to be unshifted
|
||||||
|
* @param[in] len_p Length of the polynomial coefficients
|
||||||
|
*/
|
||||||
|
void unshift_poly(fr_t *p, uint64_t len_p) {
|
||||||
|
fr_t shift_factor, factor_power;
|
||||||
|
fr_from_uint64(&shift_factor, 5); // primitive root of unity
|
||||||
|
factor_power = fr_one;
|
||||||
|
|
||||||
|
for (uint64_t i = 1; i < len_p; i++) {
|
||||||
|
fr_mul(&factor_power, &factor_power, &shift_factor);
|
||||||
|
fr_mul(&p[i], &p[i], &factor_power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a dataset with up to half the entries missing, return the reconstructed original.
|
||||||
|
*
|
||||||
|
* Assumes that the inverse FFT of the original data has the upper half of its values equal to zero.
|
||||||
|
*
|
||||||
|
* @param[out] reconstructed_data An attempted reconstruction of the original data
|
||||||
|
* @param[in] samples The data to be reconstructed, with `fr_null` set for missing values
|
||||||
|
* @param[in] len_samples The length of @p samples and @p reconstructed_data
|
||||||
|
* @param[in] fs The FFT settings previously initialised with #new_fft_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
|
||||||
|
*
|
||||||
|
* @todo Could probably reuse some memory here.
|
||||||
|
*/
|
||||||
|
C_KZG_RET recover_poly_from_samples(fr_t *reconstructed_data, fr_t *samples, uint64_t len_samples, FFTSettings *fs) {
|
||||||
|
|
||||||
|
CHECK(is_power_of_two(len_samples));
|
||||||
|
|
||||||
|
uint64_t *missing;
|
||||||
|
TRY(new_uint64_array(&missing, len_samples));
|
||||||
|
|
||||||
|
uint64_t len_missing = 0;
|
||||||
|
for (uint64_t i = 0; i < len_samples; i++) {
|
||||||
|
if (fr_is_null(&samples[i])) {
|
||||||
|
missing[len_missing++] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fr_t *zero_eval, *zero_poly;
|
||||||
|
uint64_t zero_poly_len;
|
||||||
|
TRY(new_fr_array(&zero_eval, len_samples));
|
||||||
|
TRY(new_fr_array(&zero_poly, len_samples));
|
||||||
|
TRY(zero_polynomial_via_multiplication(zero_eval, zero_poly, &zero_poly_len, len_samples, missing, len_missing,
|
||||||
|
fs));
|
||||||
|
|
||||||
|
// Check all is well
|
||||||
|
for (uint64_t i = 0; i < len_samples; i++) {
|
||||||
|
TRY(fr_is_null(&samples[i]) == fr_is_zero(&zero_eval[i]) ? C_KZG_OK : C_KZG_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Could just modify zero_eval in place?
|
||||||
|
fr_t *poly_evaluations_with_zero, *poly_with_zero;
|
||||||
|
TRY(new_fr_array(&poly_evaluations_with_zero, len_samples));
|
||||||
|
for (uint64_t i = 0; i < len_samples; i++) {
|
||||||
|
if (fr_is_null(&samples[i])) {
|
||||||
|
poly_evaluations_with_zero[i] = fr_zero;
|
||||||
|
} else {
|
||||||
|
fr_mul(&poly_evaluations_with_zero[i], &samples[i], &zero_eval[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRY(new_fr_array(&poly_with_zero, len_samples));
|
||||||
|
TRY(fft_fr(poly_with_zero, poly_evaluations_with_zero, true, len_samples, fs));
|
||||||
|
|
||||||
|
shift_poly(poly_with_zero, len_samples);
|
||||||
|
shift_poly(zero_poly, zero_poly_len); // The rest of zero_poly is 0s
|
||||||
|
|
||||||
|
// renamings:
|
||||||
|
fr_t *shifted_poly_with_zero = poly_with_zero;
|
||||||
|
fr_t *shifted_zero_poly = zero_poly;
|
||||||
|
|
||||||
|
fr_t *eval_shifted_poly_with_zero, *eval_shifted_zero_poly;
|
||||||
|
TRY(new_fr_array(&eval_shifted_poly_with_zero, len_samples));
|
||||||
|
TRY(new_fr_array(&eval_shifted_zero_poly, len_samples));
|
||||||
|
TRY(fft_fr(eval_shifted_poly_with_zero, shifted_poly_with_zero, false, len_samples, fs));
|
||||||
|
TRY(fft_fr(eval_shifted_zero_poly, shifted_zero_poly, false, len_samples, fs));
|
||||||
|
|
||||||
|
fr_t *eval_shifted_reconstructed_poly = eval_shifted_poly_with_zero;
|
||||||
|
for (uint64_t i = 0; i < len_samples; i++) {
|
||||||
|
fr_div(&eval_shifted_reconstructed_poly[i], &eval_shifted_poly_with_zero[i], &eval_shifted_zero_poly[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fr_t *shifted_reconstructed_poly;
|
||||||
|
TRY(new_fr_array(&shifted_reconstructed_poly, len_samples));
|
||||||
|
TRY(fft_fr(shifted_reconstructed_poly, eval_shifted_reconstructed_poly, true, len_samples, fs));
|
||||||
|
|
||||||
|
unshift_poly(shifted_reconstructed_poly, len_samples);
|
||||||
|
|
||||||
|
// renaming:
|
||||||
|
fr_t *reconstructed_poly = shifted_reconstructed_poly;
|
||||||
|
|
||||||
|
TRY(fft_fr(reconstructed_data, reconstructed_poly, false, len_samples, fs));
|
||||||
|
|
||||||
|
// Check all is well
|
||||||
|
for (uint64_t i = 0; i < len_samples; i++) {
|
||||||
|
TRY(fr_is_null(&samples[i]) || fr_equal(&reconstructed_data[i], &samples[i]) ? C_KZG_OK : C_KZG_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(shifted_reconstructed_poly);
|
||||||
|
free(eval_shifted_poly_with_zero);
|
||||||
|
free(eval_shifted_zero_poly);
|
||||||
|
free(poly_with_zero);
|
||||||
|
free(poly_evaluations_with_zero);
|
||||||
|
free(zero_eval);
|
||||||
|
free(zero_poly);
|
||||||
|
free(missing);
|
||||||
|
|
||||||
|
return C_KZG_OK;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Benjamin Edgington
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file recover.h */
|
||||||
|
|
||||||
|
#include "c_kzg.h"
|
||||||
|
#include "fft_common.h"
|
||||||
|
|
||||||
|
C_KZG_RET recover_poly_from_samples(fr_t *reconstructed_data, fr_t *samples, uint64_t len_samples, FFTSettings *fs);
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Benjamin Edgington
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../inc/acutest.h"
|
||||||
|
#include "c_kzg_util.h"
|
||||||
|
#include "test_util.h"
|
||||||
|
#include "recover.h"
|
||||||
|
#include "fft_fr.h"
|
||||||
|
#include "debug_util.h"
|
||||||
|
|
||||||
|
// Utility for setting a random (len_data - known) number of elements to NULL
|
||||||
|
void random_missing(fr_t *with_missing, fr_t *data, uint64_t len_data, uint64_t known) {
|
||||||
|
uint64_t *missing_idx;
|
||||||
|
TEST_CHECK(C_KZG_OK == new_uint64_array(&missing_idx, len_data));
|
||||||
|
for (uint64_t i = 0; i < len_data; i++) {
|
||||||
|
missing_idx[i] = i;
|
||||||
|
}
|
||||||
|
shuffle(missing_idx, len_data);
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < len_data; i++) {
|
||||||
|
with_missing[i] = data[i];
|
||||||
|
}
|
||||||
|
for (uint64_t i = 0; i < len_data - known; i++) {
|
||||||
|
with_missing[missing_idx[i]] = fr_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(missing_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recover_simple(void) {
|
||||||
|
FFTSettings fs;
|
||||||
|
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, 2));
|
||||||
|
|
||||||
|
fr_t poly[fs.max_width];
|
||||||
|
for (int i = 0; i < fs.max_width / 2; i++) {
|
||||||
|
fr_from_uint64(&poly[i], i);
|
||||||
|
}
|
||||||
|
for (int i = fs.max_width / 2; i < fs.max_width; i++) {
|
||||||
|
poly[i] = fr_zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
fr_t data[fs.max_width];
|
||||||
|
TEST_CHECK(C_KZG_OK == fft_fr(data, poly, false, fs.max_width, &fs));
|
||||||
|
|
||||||
|
fr_t sample[fs.max_width];
|
||||||
|
sample[0] = data[0];
|
||||||
|
sample[1] = fr_null;
|
||||||
|
sample[2] = fr_null;
|
||||||
|
sample[3] = data[3];
|
||||||
|
|
||||||
|
fr_t recovered[fs.max_width];
|
||||||
|
TEST_CHECK(C_KZG_OK == recover_poly_from_samples(recovered, sample, fs.max_width, &fs));
|
||||||
|
|
||||||
|
// Check recovered data
|
||||||
|
for (int i = 0; i < fs.max_width; i++) {
|
||||||
|
TEST_CHECK(fr_equal(&data[i], &recovered[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check against original coefficients
|
||||||
|
fr_t back[fs.max_width];
|
||||||
|
TEST_CHECK(C_KZG_OK == fft_fr(back, recovered, true, fs.max_width, &fs));
|
||||||
|
for (int i = 0; i < fs.max_width / 2; i++) {
|
||||||
|
TEST_CHECK(fr_equal(&poly[i], &back[i]));
|
||||||
|
}
|
||||||
|
for (int i = fs.max_width / 2; i < fs.max_width; i++) {
|
||||||
|
TEST_CHECK(fr_is_zero(&back[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
free_fft_settings(&fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recover_random(void) {
|
||||||
|
FFTSettings fs;
|
||||||
|
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, 12));
|
||||||
|
|
||||||
|
fr_t *poly, *data, *samples, *recovered, *back;
|
||||||
|
TEST_CHECK(C_KZG_OK == new_fr_array(&poly, fs.max_width));
|
||||||
|
TEST_CHECK(C_KZG_OK == new_fr_array(&data, fs.max_width));
|
||||||
|
TEST_CHECK(C_KZG_OK == new_fr_array(&samples, fs.max_width));
|
||||||
|
TEST_CHECK(C_KZG_OK == new_fr_array(&recovered, fs.max_width));
|
||||||
|
TEST_CHECK(C_KZG_OK == new_fr_array(&back, fs.max_width));
|
||||||
|
|
||||||
|
for (int i = 0; i < fs.max_width / 2; i++) {
|
||||||
|
fr_from_uint64(&poly[i], i);
|
||||||
|
}
|
||||||
|
for (int i = fs.max_width / 2; i < fs.max_width; i++) {
|
||||||
|
poly[i] = fr_zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CHECK(C_KZG_OK == fft_fr(data, poly, false, fs.max_width, &fs));
|
||||||
|
|
||||||
|
// Having half of the data is the minimum
|
||||||
|
for (float known_ratio = 0.5; known_ratio < 1.0; known_ratio += 0.05) {
|
||||||
|
uint64_t known = fs.max_width * known_ratio;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
random_missing(samples, data, fs.max_width, known);
|
||||||
|
|
||||||
|
TEST_CHECK(C_KZG_OK == recover_poly_from_samples(recovered, samples, fs.max_width, &fs));
|
||||||
|
for (int i = 0; i < fs.max_width; i++) {
|
||||||
|
TEST_CHECK(fr_equal(&data[i], &recovered[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check against original coefficients
|
||||||
|
fr_t back[fs.max_width];
|
||||||
|
TEST_CHECK(C_KZG_OK == fft_fr(back, recovered, true, fs.max_width, &fs));
|
||||||
|
for (int i = 0; i < fs.max_width / 2; i++) {
|
||||||
|
TEST_CHECK(fr_equal(&poly[i], &back[i]));
|
||||||
|
}
|
||||||
|
for (int i = fs.max_width / 2; i < fs.max_width; i++) {
|
||||||
|
TEST_CHECK(fr_is_zero(&back[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(poly);
|
||||||
|
free(data);
|
||||||
|
free(samples);
|
||||||
|
free(recovered);
|
||||||
|
free(back);
|
||||||
|
free_fft_settings(&fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_LIST = {
|
||||||
|
{"RECOVER_TEST", title},
|
||||||
|
{"recover_simple", recover_simple},
|
||||||
|
{"recover_random", recover_random},
|
||||||
|
{NULL, NULL} /* zero record marks the end of the list */
|
||||||
|
};
|
|
@ -21,12 +21,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "zero_poly.h"
|
#include "zero_poly.h"
|
||||||
#include "fft_fr.h"
|
|
||||||
#include "c_kzg_util.h"
|
#include "c_kzg_util.h"
|
||||||
|
#include "fft_fr.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
|
||||||
#include "debug_util.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a slice of missing indices into a leaf.
|
* Process a slice of missing indices into a leaf.
|
||||||
*
|
*
|
||||||
|
@ -141,6 +139,9 @@ C_KZG_RET reduce_leaves(fr_t *dst, uint64_t len_dst, fr_t *scratch, uint64_t len
|
||||||
*
|
*
|
||||||
* Also calculates the FFT.
|
* Also calculates the FFT.
|
||||||
*
|
*
|
||||||
|
* @remark Fails for very high numbers of missing indices. For example, with `fs.max_width = 256` and `length = 256`,
|
||||||
|
* this will fail for len_missing = 253 or more. In this case, `length` (and maybe `fs.max_width`) needs to be doubled.
|
||||||
|
*
|
||||||
* @param[out] zero_eval Array length @p length (TODO: description)
|
* @param[out] zero_eval Array length @p length (TODO: description)
|
||||||
* @param[out] zero_poly Array length @p length (TODO: description)
|
* @param[out] zero_poly Array length @p length (TODO: description)
|
||||||
* @param[out] zero_poly_len The length of the resulting @p zero_poly
|
* @param[out] zero_poly_len The length of the resulting @p zero_poly
|
||||||
|
@ -157,6 +158,11 @@ C_KZG_RET zero_polynomial_via_multiplication(fr_t *zero_eval, fr_t *zero_poly, u
|
||||||
const uint64_t *missing_indices, uint64_t len_missing,
|
const uint64_t *missing_indices, uint64_t len_missing,
|
||||||
const FFTSettings *fs) {
|
const FFTSettings *fs) {
|
||||||
if (len_missing == 0) {
|
if (len_missing == 0) {
|
||||||
|
*zero_poly_len = length;
|
||||||
|
for (uint64_t i = 0; i < length; i++) {
|
||||||
|
zero_eval[i] = fr_zero;
|
||||||
|
zero_poly[i] = fr_zero;
|
||||||
|
}
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
CHECK(length <= fs->max_width);
|
CHECK(length <= fs->max_width);
|
||||||
|
|
|
@ -246,6 +246,7 @@ void zero_poly_known(void) {
|
||||||
|
|
||||||
void zero_poly_random(void) {
|
void zero_poly_random(void) {
|
||||||
for (int its = 0; its < 8; its++) {
|
for (int its = 0; its < 8; its++) {
|
||||||
|
srand(its);
|
||||||
for (int scale = 3; scale < 13; scale++) {
|
for (int scale = 3; scale < 13; scale++) {
|
||||||
FFTSettings fs;
|
FFTSettings fs;
|
||||||
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, scale));
|
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, scale));
|
||||||
|
@ -259,6 +260,12 @@ void zero_poly_random(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: fix up the edge cases - zero_poly... fails for very large numbers of missing indices
|
||||||
|
if (len_missing == fs.max_width) {
|
||||||
|
free_fft_settings(&fs);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
fr_t *zero_eval, *zero_poly;
|
fr_t *zero_eval, *zero_poly;
|
||||||
uint64_t zero_poly_len;
|
uint64_t zero_poly_len;
|
||||||
TEST_CHECK(C_KZG_OK == new_fr_array(&zero_eval, fs.max_width));
|
TEST_CHECK(C_KZG_OK == new_fr_array(&zero_eval, fs.max_width));
|
||||||
|
|
Loading…
Reference in New Issue