diff --git a/src/c_kzg.h b/src/c_kzg.h index f699889..c0dc203 100644 --- a/src/c_kzg.h +++ b/src/c_kzg.h @@ -86,6 +86,11 @@ typedef struct { uint64_t length; /**< One more than the polynomial's degree */ } poly; +typedef struct { + fr_t *values; /**< `values[i]` is value of the polynomial at `ω^i`. */ + uint64_t length; /**< One more than the polynomial's degree */ +} poly_l; // Lagrange form + void eval_poly(fr_t *out, const poly *p, const fr_t *x); C_KZG_RET poly_inverse(poly *out, poly *b); C_KZG_RET poly_mul(poly *out, const poly *a, const poly *b); @@ -94,6 +99,7 @@ C_KZG_RET new_poly_div(poly *out, const poly *dividend, const poly *divisor); C_KZG_RET new_poly(poly *out, uint64_t length); C_KZG_RET new_poly_with_coeffs(poly *out, const fr_t *coeffs, uint64_t length); void free_poly(poly *p); +void free_poly_l(poly_l *p); // // kzg_proofs.c @@ -107,11 +113,15 @@ void free_poly(poly *p); typedef struct { const FFTSettings *fs; /**< The corresponding settings for performing FFTs */ g1_t *secret_g1; /**< G1 group elements from the trusted setup */ + g1_t *secret_g1_l; /**< secret_g1 in Lagrange form */ g2_t *secret_g2; /**< G2 group elements from the trusted setup */ uint64_t length; /**< The number of elements in secret_g1 and secret_g2 */ } KZGSettings; +C_KZG_RET new_poly_l_from_poly(poly_l *out, const poly *in, const KZGSettings *ks); + C_KZG_RET commit_to_poly(g1_t *out, const poly *p, const KZGSettings *ks); +C_KZG_RET commit_to_poly_l(g1_t *out, const poly_l *p, const KZGSettings *ks); C_KZG_RET compute_proof_single(g1_t *out, const poly *p, const fr_t *x0, const KZGSettings *ks); C_KZG_RET check_proof_single(bool *out, const g1_t *commitment, const g1_t *proof, const fr_t *x, fr_t *y, const KZGSettings *ks); diff --git a/src/kzg_proofs.c b/src/kzg_proofs.c index faf89e4..ade4a9d 100644 --- a/src/kzg_proofs.c +++ b/src/kzg_proofs.c @@ -43,6 +43,12 @@ C_KZG_RET commit_to_poly(g1_t *out, const poly *p, const KZGSettings *ks) { return C_KZG_OK; } +C_KZG_RET commit_to_poly_l(g1_t *out, const poly_l *p_l, const KZGSettings *ks) { + CHECK(p_l->length <= ks->length); + g1_linear_combination(out, ks->secret_g1_l, p_l->values, p_l->length); + return C_KZG_OK; +} + /** * Compute KZG proof for polynomial at position x0. * @@ -216,6 +222,7 @@ C_KZG_RET new_kzg_settings(KZGSettings *ks, const g1_t *secret_g1, const g2_t *s // Allocate space for the secrets TRY(new_g1_array(&ks->secret_g1, ks->length)); + TRY(new_g1_array(&ks->secret_g1_l, ks->length)); TRY(new_g2_array(&ks->secret_g2, ks->length)); // Populate the secrets @@ -225,7 +232,8 @@ C_KZG_RET new_kzg_settings(KZGSettings *ks, const g1_t *secret_g1, const g2_t *s } ks->fs = fs; - return C_KZG_OK; + // Add Lagrange form (and return its success) + return fft_g1(ks->secret_g1_l, ks->secret_g1, true, length, fs); } /** @@ -235,6 +243,7 @@ C_KZG_RET new_kzg_settings(KZGSettings *ks, const g1_t *secret_g1, const g2_t *s */ void free_kzg_settings(KZGSettings *ks) { free(ks->secret_g1); + free(ks->secret_g1_l); free(ks->secret_g2); ks->length = 0; } @@ -393,12 +402,54 @@ void commit_to_too_long_poly(void) { free_kzg_settings(&ks); } +void commit_to_poly_lagrange(void) { + // Our polynomial: degree 15, 16 coefficients + uint64_t coeffs[] = {12, 2, 8, 4, 7, 9, 1337, 227, 3, 13, 13, 130, 13, 13111, 13, 12223}; + int poly_len = sizeof coeffs / sizeof coeffs[0]; + uint64_t secrets_len = poly_len; + + FFTSettings fs; + KZGSettings ks; + g1_t s1[secrets_len]; + g2_t s2[secrets_len]; + poly p; + poly_l p_l; + g1_t commitment, commitment_l; + + // Create the polynomial + new_poly(&p, poly_len); + for (int i = 0; i < poly_len; i++) { + fr_from_uint64(&p.coeffs[i], coeffs[i]); + } + + // Initialise the secrets and data structures + generate_trusted_setup(s1, s2, &secret, secrets_len); + TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, 4)); // ln_2 of poly_len + TEST_CHECK(C_KZG_OK == new_kzg_settings(&ks, s1, s2, secrets_len, &fs)); + + // Create Lagrange form + new_poly_l_from_poly(&p_l, &p, &ks); + + // Compute commitments + TEST_CHECK(C_KZG_OK == commit_to_poly(&commitment, &p, &ks)); + TEST_CHECK(C_KZG_OK == commit_to_poly_l(&commitment_l, &p_l, &ks)); + + // Check commitments are equal + TEST_CHECK(g1_equal(&commitment, &commitment_l)); + + free_fft_settings(&fs); + free_kzg_settings(&ks); + free_poly(&p); + free_poly_l(&p_l); +} + TEST_LIST = { {"KZG_PROOFS_TEST", title}, {"proof_single", proof_single}, {"proof_multi", proof_multi}, {"commit_to_nil_poly", commit_to_nil_poly}, {"commit_to_too_long_poly", commit_to_too_long_poly}, + {"commit_to_poly_lagrange", commit_to_poly_lagrange}, {NULL, NULL} /* zero record marks the end of the list */ }; diff --git a/src/poly.c b/src/poly.c index dbe1808..28a7323 100644 --- a/src/poly.c +++ b/src/poly.c @@ -541,6 +541,11 @@ C_KZG_RET new_poly(poly *out, uint64_t length) { return new_fr_array(&out->coeffs, length); } +C_KZG_RET new_poly_l(poly_l *out, uint64_t length) { + out->length = length; + return new_fr_array(&out->values, length); +} + /** * Initialise a polynomial of the given size with the given coefficients. * @@ -562,6 +567,11 @@ C_KZG_RET new_poly_with_coeffs(poly *out, const fr_t *coeffs, uint64_t length) { return C_KZG_OK; } +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); +} + /** * Reclaim the memory used by a polynomial. * @@ -576,6 +586,12 @@ void free_poly(poly *p) { } } +void free_poly_l(poly_l *p) { + if (p->values != NULL) { + free(p->values); + } +} + #ifdef KZGTEST #include "../inc/acutest.h"