Support zero length polynomials
This commit is contained in:
parent
b3fd3cbb72
commit
f93c33c2db
|
@ -51,10 +51,8 @@ bool check_proof_single(const KZGSettings *ks, const blst_p1 *commitment, const
|
||||||
// of several polynomial evaluations)
|
// of several polynomial evaluations)
|
||||||
C_KZG_RET compute_proof_multi(blst_p1 *out, const KZGSettings *ks, poly *p, const blst_fr *x0, uint64_t n) {
|
C_KZG_RET compute_proof_multi(blst_p1 *out, const KZGSettings *ks, poly *p, const blst_fr *x0, uint64_t n) {
|
||||||
poly divisor, q;
|
poly divisor, q;
|
||||||
uint64_t len;
|
|
||||||
blst_fr x_pow_n;
|
blst_fr x_pow_n;
|
||||||
|
C_KZG_RET ret;
|
||||||
ASSERT(p->length >= n + 1, 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))
|
||||||
init_poly(&divisor, n + 1);
|
init_poly(&divisor, n + 1);
|
||||||
|
@ -72,10 +70,10 @@ C_KZG_RET compute_proof_multi(blst_p1 *out, const KZGSettings *ks, poly *p, cons
|
||||||
divisor.coeffs[n] = fr_one;
|
divisor.coeffs[n] = fr_one;
|
||||||
|
|
||||||
// Calculate q = p / (x^n - x0^n)
|
// Calculate q = p / (x^n - x0^n)
|
||||||
// Discard the return codes since we already checked above that all should be fine.
|
init_poly(&q, poly_quotient_length(p, &divisor));
|
||||||
poly_quotient_length(&len, p, &divisor);
|
if ((ret = poly_long_div(&q, p, &divisor) != C_KZG_OK)) {
|
||||||
init_poly(&q, len);
|
return C_KZG_ERROR;
|
||||||
poly_long_div(&q, p, &divisor);
|
}
|
||||||
|
|
||||||
commit_to_poly(out, ks, &q);
|
commit_to_poly(out, ks, &q);
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,10 @@ void proof_single(void) {
|
||||||
// Verify the proof that the (unknown) polynomial has y = value at x = 25
|
// Verify the proof that the (unknown) polynomial has y = value at x = 25
|
||||||
TEST_CHECK(true == check_proof_single(&ks, &commitment, &proof, &x, &value));
|
TEST_CHECK(true == check_proof_single(&ks, &commitment, &proof, &x, &value));
|
||||||
|
|
||||||
|
// Change the value and check that the proof fails
|
||||||
|
blst_fr_add(&value, &value, &fr_one);
|
||||||
|
TEST_CHECK(false == check_proof_single(&ks, &commitment, &proof, &x, &value));
|
||||||
|
|
||||||
free_fft_settings(&fs);
|
free_fft_settings(&fs);
|
||||||
free_poly(&p);
|
free_poly(&p);
|
||||||
free(s1);
|
free(s1);
|
||||||
|
@ -85,20 +89,21 @@ void proof_multi(void) {
|
||||||
// Our polynomial: degree 15, 16 coefficients
|
// Our polynomial: degree 15, 16 coefficients
|
||||||
uint64_t coeffs[] = {1, 2, 3, 4, 7, 7, 7, 7, 13, 13, 13, 13, 13, 13, 13, 13};
|
uint64_t coeffs[] = {1, 2, 3, 4, 7, 7, 7, 7, 13, 13, 13, 13, 13, 13, 13, 13};
|
||||||
int poly_len = sizeof coeffs / sizeof coeffs[0];
|
int poly_len = sizeof coeffs / sizeof coeffs[0];
|
||||||
uint64_t secrets_len = poly_len + 1;
|
|
||||||
|
|
||||||
FFTSettings fs1, fs2;
|
FFTSettings fs1, fs2;
|
||||||
KZGSettings ks1, ks2;
|
KZGSettings ks1, ks2;
|
||||||
poly p;
|
poly p;
|
||||||
blst_p1 commitment, proof;
|
blst_p1 commitment, proof;
|
||||||
blst_p1 *s1 = malloc(secrets_len * sizeof(blst_p1));
|
|
||||||
blst_p2 *s2 = malloc(secrets_len * sizeof(blst_p2));
|
|
||||||
blst_fr x, tmp;
|
blst_fr x, tmp;
|
||||||
|
|
||||||
// Must have coset_scale < poly_len [TODO: why?]
|
// Compute proof at 2^coset_scale points
|
||||||
int coset_scale = 3, coset_len = (1 << coset_scale);
|
int coset_scale = 7, coset_len = (1 << coset_scale);
|
||||||
blst_fr y[coset_len];
|
blst_fr y[coset_len];
|
||||||
|
|
||||||
|
uint64_t secrets_len = poly_len > coset_len ? poly_len + 1 : coset_len + 1;
|
||||||
|
blst_p1 *s1 = malloc(secrets_len * sizeof(blst_p1));
|
||||||
|
blst_p2 *s2 = malloc(secrets_len * sizeof(blst_p2));
|
||||||
|
|
||||||
// Create the polynomial
|
// Create the polynomial
|
||||||
init_poly(&p, poly_len);
|
init_poly(&p, poly_len);
|
||||||
for (int i = 0; i < poly_len; i++) {
|
for (int i = 0; i < poly_len; i++) {
|
||||||
|
@ -127,7 +132,11 @@ void proof_multi(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the proof that the (unknown) polynomial has value y_i at x_i
|
// Verify the proof that the (unknown) polynomial has value y_i at x_i
|
||||||
TEST_CHECK(check_proof_multi(&ks2, &commitment, &proof, &x, y, coset_len));
|
TEST_CHECK(true == check_proof_multi(&ks2, &commitment, &proof, &x, y, coset_len));
|
||||||
|
|
||||||
|
// Change a value and check that the proof fails
|
||||||
|
blst_fr_add(y + coset_len / 2, y + coset_len / 2, &fr_one);
|
||||||
|
TEST_CHECK(false == check_proof_multi(&ks2, &commitment, &proof, &x, y, coset_len));
|
||||||
|
|
||||||
free_fft_settings(&fs1);
|
free_fft_settings(&fs1);
|
||||||
free_fft_settings(&fs2);
|
free_fft_settings(&fs2);
|
||||||
|
@ -136,26 +145,10 @@ void proof_multi(void) {
|
||||||
free(s2);
|
free(s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void proof_single_error(void) {
|
|
||||||
poly p;
|
|
||||||
blst_p1 proof;
|
|
||||||
KZGSettings ks;
|
|
||||||
blst_fr x;
|
|
||||||
|
|
||||||
// Check it barfs on a constant polynomial
|
|
||||||
init_poly(&p, 1);
|
|
||||||
|
|
||||||
fr_from_uint64(&x, 1234);
|
|
||||||
TEST_CHECK(C_KZG_BADARGS == compute_proof_single(&proof, &ks, &p, &x));
|
|
||||||
|
|
||||||
free_poly(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_LIST =
|
TEST_LIST =
|
||||||
{
|
{
|
||||||
{"KZG_PROOFS_TEST", title},
|
{"KZG_PROOFS_TEST", title},
|
||||||
{"proof_single", proof_single},
|
{"proof_single", proof_single},
|
||||||
{"proof_multi", proof_multi},
|
{"proof_multi", proof_multi},
|
||||||
{"proof_single_error", proof_single},
|
|
||||||
{ NULL, NULL } /* zero record marks the end of the list */
|
{ NULL, NULL } /* zero record marks the end of the list */
|
||||||
};
|
};
|
||||||
|
|
26
src/poly.c
26
src/poly.c
|
@ -23,11 +23,13 @@ static void poly_factor_div(blst_fr *out, const blst_fr *a, const blst_fr *b) {
|
||||||
|
|
||||||
void init_poly(poly *out, const uint64_t length) {
|
void init_poly(poly *out, const uint64_t length) {
|
||||||
out->length = length;
|
out->length = length;
|
||||||
out->coeffs = malloc(length * sizeof(blst_fr));
|
out->coeffs = length > 0 ? malloc(length * sizeof(blst_fr)): NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_poly(poly *p) {
|
void free_poly(poly *p) {
|
||||||
free(p->coeffs);
|
if (p->coeffs != NULL) {
|
||||||
|
free(p->coeffs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void eval_poly(blst_fr *out, const poly *p, const blst_fr *x) {
|
void eval_poly(blst_fr *out, const poly *p, const blst_fr *x) {
|
||||||
|
@ -55,28 +57,28 @@ void eval_poly(blst_fr *out, const poly *p, const blst_fr *x) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this to find out how much space to allocate for the result
|
// Call this to find out how much space to allocate for the result of `poly_long_div()`
|
||||||
C_KZG_RET poly_quotient_length(uint64_t *out, const poly *dividend, const poly *divisor) {
|
uint64_t poly_quotient_length(const poly *dividend, const poly *divisor) {
|
||||||
ASSERT(dividend->length >= divisor->length, C_KZG_BADARGS);
|
return dividend->length >= divisor->length ? dividend->length - divisor->length + 1 : 0;
|
||||||
*out = dividend->length - divisor->length + 1;
|
|
||||||
return C_KZG_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `out` must have been pre-allocated to the correct size, and the length is provided
|
// `out` must have been pre-allocated to the correct size, see `poly_quotient_length()`
|
||||||
// as a check
|
|
||||||
C_KZG_RET poly_long_div(poly *out, const poly *dividend, const poly *divisor) {
|
C_KZG_RET poly_long_div(poly *out, const poly *dividend, const poly *divisor) {
|
||||||
uint64_t a_pos = dividend->length - 1;
|
uint64_t a_pos = dividend->length - 1;
|
||||||
uint64_t b_pos = divisor->length - 1;
|
uint64_t b_pos = divisor->length - 1;
|
||||||
uint64_t diff = a_pos - b_pos;
|
uint64_t diff = a_pos - b_pos;
|
||||||
blst_fr a[dividend->length];
|
blst_fr a[dividend->length];
|
||||||
|
|
||||||
ASSERT(out->length == diff + 1, C_KZG_BADARGS);
|
ASSERT(out->length == poly_quotient_length(dividend, divisor), C_KZG_BADARGS);
|
||||||
|
|
||||||
|
// If the divisor is larger than the dividend, the result is zero-length
|
||||||
|
if (divisor->length > dividend->length) return C_KZG_OK;
|
||||||
|
|
||||||
for (uint64_t i = 0; i < dividend->length; i++) {
|
for (uint64_t i = 0; i < dividend->length; i++) {
|
||||||
a[i] = dividend->coeffs[i];
|
a[i] = dividend->coeffs[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (diff > 0) {
|
||||||
poly_factor_div(&out->coeffs[diff], &a[a_pos], &divisor->coeffs[b_pos]);
|
poly_factor_div(&out->coeffs[diff], &a[a_pos], &divisor->coeffs[b_pos]);
|
||||||
for (uint64_t i = 0; i <= b_pos; i++) {
|
for (uint64_t i = 0; i <= b_pos; i++) {
|
||||||
blst_fr tmp;
|
blst_fr tmp;
|
||||||
|
@ -84,10 +86,10 @@ C_KZG_RET poly_long_div(poly *out, const poly *dividend, const poly *divisor) {
|
||||||
blst_fr_mul(&tmp, &out->coeffs[diff], &divisor->coeffs[i]);
|
blst_fr_mul(&tmp, &out->coeffs[diff], &divisor->coeffs[i]);
|
||||||
blst_fr_sub(&a[diff + i], &a[diff + i], &tmp);
|
blst_fr_sub(&a[diff + i], &a[diff + i], &tmp);
|
||||||
}
|
}
|
||||||
if (diff == 0) break;
|
|
||||||
--diff;
|
--diff;
|
||||||
--a_pos;
|
--a_pos;
|
||||||
}
|
}
|
||||||
|
poly_factor_div(&out->coeffs[0], &a[a_pos], &divisor->coeffs[b_pos]);
|
||||||
|
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,5 +26,5 @@ typedef struct {
|
||||||
void init_poly(poly *out, const uint64_t length);
|
void init_poly(poly *out, const uint64_t length);
|
||||||
void free_poly(poly *p);
|
void free_poly(poly *p);
|
||||||
void eval_poly(blst_fr *out, const poly *p, const blst_fr *x);
|
void eval_poly(blst_fr *out, const poly *p, const blst_fr *x);
|
||||||
C_KZG_RET poly_quotient_length(uint64_t *out, const poly *dividend, const poly *divisor);
|
uint64_t poly_quotient_length(const poly *dividend, const poly *divisor);
|
||||||
C_KZG_RET poly_long_div(poly *out, const poly *dividend, const poly *divisor);
|
C_KZG_RET poly_long_div(poly *out, const poly *dividend, const poly *divisor);
|
||||||
|
|
|
@ -22,19 +22,11 @@ void title(void) {;}
|
||||||
|
|
||||||
void poly_div_length(void) {
|
void poly_div_length(void) {
|
||||||
poly a, b;
|
poly a, b;
|
||||||
uint64_t len;
|
|
||||||
init_poly(&a, 17);
|
init_poly(&a, 17);
|
||||||
init_poly(&b, 5);
|
init_poly(&b, 5);
|
||||||
TEST_CHECK(C_KZG_OK == poly_quotient_length(&len, &a, &b));
|
TEST_CHECK(13 == poly_quotient_length(&a, &b));
|
||||||
TEST_CHECK(13 == len);
|
TEST_CHECK(1 == poly_quotient_length(&a, &a));
|
||||||
}
|
TEST_CHECK(0 == poly_quotient_length(&b, &a));
|
||||||
|
|
||||||
void poly_div_length_bad(void) {
|
|
||||||
poly a, b;
|
|
||||||
uint64_t len;
|
|
||||||
init_poly(&a, 5);
|
|
||||||
init_poly(&b, 17);
|
|
||||||
TEST_CHECK(C_KZG_BADARGS == poly_quotient_length(&len, &a, &b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void poly_div_0(void) {
|
void poly_div_0(void) {
|
||||||
|
@ -106,14 +98,35 @@ void poly_div_1(void) {
|
||||||
TEST_CHECK(fr_equal(&expected[2], &actual.coeffs[2]));
|
TEST_CHECK(fr_equal(&expected[2], &actual.coeffs[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void poly_wrong_size(void) {
|
void poly_div_2(void) {
|
||||||
poly dividend, divisor, result;
|
blst_fr a[3], b[2];
|
||||||
TEST_CHECK(C_KZG_BADARGS == poly_long_div(&result, ÷nd, &divisor));
|
poly dividend, divisor, actual;
|
||||||
|
|
||||||
|
// Calculate (x + 1) / (x^2 - 1) = nil
|
||||||
|
|
||||||
|
// Dividend
|
||||||
|
fr_from_uint64(&b[0], 1);
|
||||||
|
fr_from_uint64(&b[1], 1);
|
||||||
|
dividend.length = 2;
|
||||||
|
dividend.coeffs = b;
|
||||||
|
|
||||||
|
// Divisor
|
||||||
|
fr_from_uint64(&a[0], 1);
|
||||||
|
fr_negate(&a[0], &a[0]);
|
||||||
|
fr_from_uint64(&a[1], 0);
|
||||||
|
fr_from_uint64(&a[2], 1);
|
||||||
|
divisor.length = 3;
|
||||||
|
divisor.coeffs = a;
|
||||||
|
|
||||||
|
init_poly(&actual, poly_quotient_length(÷nd, &divisor));
|
||||||
|
|
||||||
|
TEST_CHECK(C_KZG_OK == poly_long_div(&actual, ÷nd, &divisor));
|
||||||
|
TEST_CHECK(fr_equal(NULL, actual.coeffs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void poly_eval_check(void) {
|
void poly_eval_check(void) {
|
||||||
uint64_t n = 10;
|
uint64_t n = 10;
|
||||||
blst_fr res, expected;
|
blst_fr actual, expected;
|
||||||
poly p;
|
poly p;
|
||||||
init_poly(&p, n);
|
init_poly(&p, n);
|
||||||
for (uint64_t i = 0; i < n; i++) {
|
for (uint64_t i = 0; i < n; i++) {
|
||||||
|
@ -121,14 +134,14 @@ void poly_eval_check(void) {
|
||||||
}
|
}
|
||||||
fr_from_uint64(&expected, n * (n + 1) / 2);
|
fr_from_uint64(&expected, n * (n + 1) / 2);
|
||||||
|
|
||||||
eval_poly(&res, &p, &fr_one);
|
eval_poly(&actual, &p, &fr_one);
|
||||||
|
|
||||||
TEST_CHECK(fr_equal(&expected, &res));
|
TEST_CHECK(fr_equal(&expected, &actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
void poly_eval_0_check(void) {
|
void poly_eval_0_check(void) {
|
||||||
uint64_t n = 7, a = 597;
|
uint64_t n = 7, a = 597;
|
||||||
blst_fr res, expected;
|
blst_fr actual, expected;
|
||||||
poly p;
|
poly p;
|
||||||
init_poly(&p, n);
|
init_poly(&p, n);
|
||||||
for (uint64_t i = 0; i < n; i++) {
|
for (uint64_t i = 0; i < n; i++) {
|
||||||
|
@ -136,20 +149,31 @@ void poly_eval_0_check(void) {
|
||||||
}
|
}
|
||||||
fr_from_uint64(&expected, a);
|
fr_from_uint64(&expected, a);
|
||||||
|
|
||||||
eval_poly(&res, &p, &fr_zero);
|
eval_poly(&actual, &p, &fr_zero);
|
||||||
|
|
||||||
TEST_CHECK(fr_equal(&expected, &res));
|
TEST_CHECK(fr_equal(&expected, &actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
void poly_eval_nil_check(void) {
|
||||||
|
uint64_t n = 0;
|
||||||
|
blst_fr actual;
|
||||||
|
poly p;
|
||||||
|
init_poly(&p, n);
|
||||||
|
|
||||||
|
eval_poly(&actual, &p, &fr_one);
|
||||||
|
|
||||||
|
TEST_CHECK(fr_equal(&fr_zero, &actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_LIST =
|
TEST_LIST =
|
||||||
{
|
{
|
||||||
{"POLY_TEST", title},
|
{"POLY_TEST", title},
|
||||||
{"poly_div_length", poly_div_length},
|
{"poly_div_length", poly_div_length},
|
||||||
{"poly_div_length_bad", poly_div_length_bad},
|
|
||||||
{"poly_div_0", poly_div_0},
|
{"poly_div_0", poly_div_0},
|
||||||
{"poly_div_1", poly_div_1},
|
{"poly_div_1", poly_div_1},
|
||||||
{"poly_wrong_size", poly_wrong_size},
|
{"poly_div_2", poly_div_1},
|
||||||
{"poly_eval_check", poly_eval_check},
|
{"poly_eval_check", poly_eval_check},
|
||||||
{"poly_eval_0_check", poly_eval_0_check},
|
{"poly_eval_0_check", poly_eval_0_check},
|
||||||
|
{"poly_eval_nil_check", poly_eval_0_check},
|
||||||
{ NULL, NULL } /* zero record marks the end of the list */
|
{ NULL, NULL } /* zero record marks the end of the list */
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue