diff --git a/src/c_kzg.h b/src/c_kzg.h index c0dc203..f7e9536 100644 --- a/src/c_kzg.h +++ b/src/c_kzg.h @@ -92,6 +92,7 @@ typedef struct { } poly_l; // Lagrange form void eval_poly(fr_t *out, const poly *p, const fr_t *x); +void eval_poly_l(fr_t *out, const poly_l *p, const fr_t *x, const FFTSettings *fs); C_KZG_RET poly_inverse(poly *out, poly *b); C_KZG_RET poly_mul(poly *out, const poly *a, const poly *b); C_KZG_RET poly_mul_(poly *out, const poly *a, const poly *b, FFTSettings *fs); diff --git a/src/kzg_proofs.c b/src/kzg_proofs.c index ade4a9d..57f9309 100644 --- a/src/kzg_proofs.c +++ b/src/kzg_proofs.c @@ -443,8 +443,46 @@ void commit_to_poly_lagrange(void) { free_poly_l(&p_l); } +void poly_eval_l_check(void) { + uint64_t n = 10; + fr_t actual, expected; + poly p; + new_poly(&p, n); + for (uint64_t i = 0; i < n; i++) { + fr_from_uint64(&p.coeffs[i], i + 1); + } + fr_t x; + fr_from_uint64(&x, 39); + // x = fr_one; + eval_poly(&expected, &p, &x); + + poly_l p_l; + FFTSettings fs; + KZGSettings ks; + uint64_t secrets_len = 16; + g1_t s1[secrets_len]; + g2_t s2[secrets_len]; + g1_t result; + + generate_trusted_setup(s1, s2, &secret, secrets_len); + TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, 4)); // log_2(secrets_len) + TEST_CHECK(C_KZG_OK == new_kzg_settings(&ks, s1, s2, secrets_len, &fs)); + + TEST_CHECK(C_KZG_OK == new_poly_l_from_poly(&p_l, &p, &ks)); + + eval_poly_l(&actual, &p_l, &x, &fs); + + TEST_CHECK(fr_equal(&expected, &actual)); + + free_fft_settings(&fs); + free_kzg_settings(&ks); + free_poly(&p); + free_poly_l(&p_l); +} + TEST_LIST = { {"KZG_PROOFS_TEST", title}, + {"poly_eval_l_check", poly_eval_l_check}, {"proof_single", proof_single}, {"proof_multi", proof_multi}, {"commit_to_nil_poly", commit_to_nil_poly}, diff --git a/src/poly.c b/src/poly.c index 28a7323..892fe18 100644 --- a/src/poly.c +++ b/src/poly.c @@ -102,6 +102,29 @@ void eval_poly(fr_t *out, const poly *p, const fr_t *x) { } } +// TODO: optimize via batch inversion +void eval_poly_l(fr_t *out, const poly_l *p, const fr_t *x, const FFTSettings *fs) { + fr_t tmp, tmp2, tmp3; + uint64_t i; + const uint64_t stride = fs->max_width / p->length; + + *out = fr_zero; + for (i = 0; i < p->length; i++) { + fr_sub(&tmp, x, &fs->expanded_roots_of_unity[i * stride]); + fr_inv(&tmp2, &tmp); + fr_mul(&tmp, &tmp2, &fs->expanded_roots_of_unity[i * stride]); + fr_mul(&tmp2, &tmp, &p->values[i]); + fr_add(out, out, &tmp2); + } + fr_negate(&tmp3, &fr_one); + fr_pow(&tmp2, x, p->length); + fr_sub(&tmp, &tmp2, &fr_one); + fr_from_uint64(&tmp2, p->length); + fr_div(&tmp3, &tmp, &tmp2); + tmp2 = *out; + fr_mul(out, &tmp2, &tmp3); +} + /** * Polynomial division in the finite field via long division. * @@ -569,7 +592,21 @@ C_KZG_RET new_poly_with_coeffs(poly *out, const fr_t *coeffs, uint64_t length) { C_KZG_RET new_poly_l_from_poly(poly_l *out, const poly *in, const KZGSettings *ks) { TRY(new_poly_l(out, ks->length)); - return fft_fr(out->values, in->coeffs, false, out->length, ks->fs); + if (out->length <= in->length) { + return fft_fr(out->values, in->coeffs, false, out->length, ks->fs); + } + else { + int i; + fr_t *coeffs; + TRY(new_fr_array(&coeffs, out->length)); + for (i = 0; i < in->length; i++) { + coeffs[i] = in->coeffs[i]; + } + for (; i < out->length; i++) { + coeffs[i] = fr_zero; + } + return fft_fr(out->values, coeffs, false, out->length, ks->fs); + } } /**