Interface changes to free the blobs (#123)

* Update C files to new interface

* Switch CHALLENGE_INPUT_SIZE from a macro to a `const int`.

* Update README with the new public methods

---------

Co-authored-by: Justin Traglia <jtraglia@pm.me>
This commit is contained in:
George Kadianakis 2023-02-20 17:52:12 +02:00 committed by GitHub
parent f87eee57d3
commit 46d529cf00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 443 additions and 251 deletions

View File

@ -5,9 +5,10 @@ This is a copy of [C-KZG](https://github.com/benjaminion/c-kzg) stripped-down to
- `blob_to_kzg_commitment`
- `compute_kzg_proof`
- `compute_aggregate_kzg_proof`
- `verify_kzg_proof`
- `verify_aggregate_kzg_proof`
- `compute_blob_kzg_proof`
- `verify_blob_kzg_proof`
- `verify_blob_kzg_proof_batch`
We also provide functions for loading/freeing the trusted setup:

View File

@ -21,6 +21,7 @@
*/
#include "c_kzg_4844.h"
#include <assert.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
@ -38,8 +39,9 @@
// clang-format off
/** The Fiat-Shamir protocol domain. */
/** The Fiat-Shamir protocol domains. */
static const char *FIAT_SHAMIR_PROTOCOL_DOMAIN = "FSBLOBVERIFY_V1_";
static const char *RANDOM_CHALLENGE_KZG_BATCH_DOMAIN = "RCKZGBATCH___V1_";
/** Deserialized form of the G1 identity/infinity point. */
static const g1_t G1_IDENTITY = {
@ -650,10 +652,8 @@ static C_KZG_RET validate_kzg_g1(g1_t *out, const Bytes48 *b) {
/* The point at infinity is accepted! */
if (blst_p1_is_inf(out)) return C_KZG_OK;
/* The point must be on the curve */
if (!blst_p1_on_curve(out)) return C_KZG_BADARGS;
/* The point must be on the right subgroup */
if (!blst_p1_in_g1(out)) return C_KZG_BADARGS;
@ -698,37 +698,24 @@ static C_KZG_RET blob_to_polynomial(Polynomial *p, const Blob *blob) {
return C_KZG_OK;
}
/* Forward function definition */
static void compute_powers(fr_t *out, fr_t *x, uint64_t n);
/* Input size to the Fiat-Shamir challenge computation */
static const int CHALLENGE_INPUT_SIZE = 32 + BYTES_PER_BLOB + 48;
/**
* Return the Fiat-Shamir challenges required by the rest of the protocol.
* Return the Fiat-Shamir challenge required to verify `blob` and `commitment`.
*
* @remark This function should compute challenges even if `n==0`.
*
* @param[out] eval_challenge_out The evaluation challenge
* @param[out] r_powers_out The powers of r, where r is a randomly
* generated scalar
* @param[in] polys The array of polynomials
* @param[in] comms The array of commitments
* @param[in] blob A blob
* @param[in] commitment A commitment
* @param[in] n The number of polynomials and commitments
*/
static C_KZG_RET compute_challenges(
fr_t *eval_challenge_out,
fr_t *r_powers_out,
const Polynomial *polys,
const g1_t *comms,
uint64_t n
static void compute_challenge(
fr_t *eval_challenge_out, const Blob *blob, const g1_t *commitment
) {
C_KZG_RET ret;
size_t i;
uint64_t j;
uint8_t *bytes = NULL;
// len(FIAT_SHAMIR_PROTOCOL_DOMAIN) + 8 + 8 + n blobs + n commitments
size_t input_size = 32 + (n * BYTES_PER_BLOB) + (n * 48);
ret = c_kzg_malloc((void **)&bytes, input_size);
if (ret != C_KZG_OK) goto out;
Bytes32 eval_challenge;
uint8_t bytes[CHALLENGE_INPUT_SIZE];
/* Pointer tracking `bytes` for writing on top of it */
uint8_t *offset = bytes;
@ -736,52 +723,27 @@ static C_KZG_RET compute_challenges(
/* Copy domain separator */
memcpy(offset, FIAT_SHAMIR_PROTOCOL_DOMAIN, 16);
offset += 16;
bytes_from_uint64(
offset, 0
); /* need to fill 16 bytes with the degree in little-endian */
offset += 8;
bytes_from_uint64(offset, FIELD_ELEMENTS_PER_BLOB);
offset += 8;
bytes_from_uint64(offset, n);
offset += 8;
/* Copy polynomials */
for (i = 0; i < n; i++) {
for (j = 0; j < FIELD_ELEMENTS_PER_BLOB; j++) {
bytes_from_bls_field((Bytes32 *)offset, &polys[i].evals[j]);
offset += BYTES_PER_FIELD_ELEMENT;
}
}
/* Copy blob */
memcpy(offset, blob->bytes, BYTES_PER_BLOB);
offset += BYTES_PER_BLOB;
/* Copy commitments */
for (i = 0; i < n; i++) {
bytes_from_g1((Bytes48 *)offset, &comms[i]);
offset += BYTES_PER_COMMITMENT;
}
/* Copy commitment */
bytes_from_g1((Bytes48 *)offset, commitment);
offset += BYTES_PER_COMMITMENT;
/* Now let's create challenges! */
uint8_t hashed_data[32] = {0};
blst_sha256(hashed_data, bytes, input_size);
/* Make sure we wrote the entire buffer */
assert(offset == bytes + CHALLENGE_INPUT_SIZE);
/* We will use hash_input in the computation of both challenges */
uint8_t hash_input[33];
/* Compute r */
Bytes32 r_bytes;
memcpy(hash_input, hashed_data, 32);
hash_input[32] = 0x0;
blst_sha256(r_bytes.bytes, hash_input, 33);
/* Compute r_powers */
fr_t r;
hash_to_bls_field(&r, &r_bytes);
compute_powers(r_powers_out, &r, n);
/* Compute eval_challenge */
Bytes32 eval_challenge;
hash_input[32] = 0x1;
blst_sha256(eval_challenge.bytes, hash_input, 33);
/* Now let's create the challenge! */
blst_sha256(eval_challenge.bytes, bytes, CHALLENGE_INPUT_SIZE);
hash_to_bls_field(eval_challenge_out, &eval_challenge);
out:
free(bytes);
return ret;
}
/**
@ -859,33 +821,6 @@ out:
return ret;
}
/**
* Given an array of polynomials, interpret it as a 2D matrix and compute
* the linear combination of each column with a set of scalars: return the
* resulting polynomial.
*
* @remark If `n==0` then this function should return the zero polynomial.
*
* @param[out] out The result polynomial
* @param[in] vectors The array of polynomials to be combined
* @param[in] scalars The array of scalars to multiply the polynomials with
* @param[in] n The number of polynomials and scalars
*/
static void poly_lincomb(
Polynomial *out, const Polynomial *vectors, const fr_t *scalars, uint64_t n
) {
fr_t tmp;
uint64_t i, j;
for (j = 0; j < FIELD_ELEMENTS_PER_BLOB; j++)
out->evals[j] = FR_ZERO;
for (i = 0; i < n; i++) {
for (j = 0; j < FIELD_ELEMENTS_PER_BLOB; j++) {
blst_fr_mul(&tmp, &scalars[i], &vectors[i].evals[j]);
blst_fr_add(&out->evals[j], &out->evals[j], &tmp);
}
}
}
/**
* Compute and return [ x^0, x^1, ..., x^{n-1} ].
*
@ -1090,7 +1025,7 @@ static C_KZG_RET verify_kzg_proof_impl(
}
/* Forward function declaration */
C_KZG_RET compute_kzg_proof_impl(
static C_KZG_RET compute_kzg_proof_impl(
KZGProof *out,
const Polynomial *polynomial,
const fr_t *z,
@ -1137,7 +1072,7 @@ out:
* @param[in] s The settings containing the secrets, previously
* initialised with #new_kzg_settings
*/
C_KZG_RET compute_kzg_proof_impl(
static C_KZG_RET compute_kzg_proof_impl(
KZGProof *out,
const Polynomial *polynomial,
const fr_t *z,
@ -1218,170 +1153,330 @@ out:
}
/**
* Given a list of polynomials and commitments, compute and return:
* 1. the aggregated polynomial
* 2. the aggregated KZG commitment,
* 3. the polynomial evaluation random challenge.
* Given a blob, return the KZG proof that is used to verify it against the
* commitment.
*
* @remark This function should work even if `n==0`.
*
* @param[out] poly_out The output aggregated polynomial
* @param[out] comm_out The output aggregated commitment
* @param[out] chal_out The output evaluation challenge
* @param[in] polys Array of polynomials
* @param[in] kzg_commitments Array of KZG commitments
* @param[in] n Number of polynomials and commitments
* @param[out] out The resulting proof
* @param[in] blob A blob
* @param[in] s The trusted setup
*/
static C_KZG_RET compute_aggregated_poly_and_commitment(
Polynomial *poly_out,
g1_t *comm_out,
fr_t *chal_out,
const Polynomial *polys,
const g1_t *kzg_commitments,
size_t n
C_KZG_RET compute_blob_kzg_proof(
KZGProof *out, const Blob *blob, const KZGSettings *s
) {
C_KZG_RET ret;
fr_t *r_powers = NULL;
Polynomial polynomial;
g1_t commitment_g1;
fr_t evaluation_challenge_fr;
if (n > 0) {
ret = new_fr_array(&r_powers, n);
if (ret != C_KZG_OK) goto out;
}
ret = compute_challenges(chal_out, r_powers, polys, kzg_commitments, n);
ret = blob_to_polynomial(&polynomial, blob);
if (ret != C_KZG_OK) goto out;
poly_lincomb(poly_out, polys, r_powers, n);
ret = poly_to_kzg_commitment(&commitment_g1, &polynomial, s);
if (ret != C_KZG_OK) goto out;
ret = g1_lincomb(comm_out, kzg_commitments, r_powers, n);
compute_challenge(&evaluation_challenge_fr, blob, &commitment_g1);
ret = compute_kzg_proof_impl(out, &polynomial, &evaluation_challenge_fr, s);
if (ret != C_KZG_OK) goto out;
out:
free(r_powers);
return ret;
}
/**
* Computes aggregate KZG proof given for multiple blobs.
* Given a blob and its proof, verify that it corresponds to the provided
* commitment.
*
* @remark This function should work even if `n==0`.
*
* @param[out] out The output aggregate KZG proof.
* @param[in] blobs Array of blobs to compute the aggregate proof for
* @param[in] n The number of blobs in the array
* @param[in] s The settings struct containing the commitment key
* (i.e. the trusted setup)
* @param[out] ok `true` if the proof is valid, `false` if not
* @param[in] blob Blob to verify
* @param[in] commitment_bytes Commitment to verify
* @param[in] proof_bytes Proof used for verification
* @param[in] s The settings struct containing the commitment
* verification key (i.e. the trusted setup)
*/
C_KZG_RET compute_aggregate_kzg_proof(
KZGProof *out, const Blob *blobs, size_t n, const KZGSettings *s
) {
C_KZG_RET ret;
g1_t *commitments = NULL;
Polynomial *polys = NULL;
if (n > 0) {
ret = new_g1_array(&commitments, n);
if (ret != C_KZG_OK) goto out;
ret = c_kzg_calloc((void **)&polys, n, sizeof(Polynomial));
if (ret != C_KZG_OK) goto out;
}
for (size_t i = 0; i < n; i++) {
ret = blob_to_polynomial(&polys[i], &blobs[i]);
if (ret != C_KZG_OK) goto out;
ret = poly_to_kzg_commitment(&commitments[i], &polys[i], s);
if (ret != C_KZG_OK) goto out;
}
Polynomial aggregated_poly;
g1_t aggregated_poly_commitment;
fr_t evaluation_challenge;
ret = compute_aggregated_poly_and_commitment(
&aggregated_poly,
&aggregated_poly_commitment,
&evaluation_challenge,
polys,
commitments,
n
);
if (ret != C_KZG_OK) goto out;
ret = compute_kzg_proof_impl(
out, &aggregated_poly, &evaluation_challenge, s
);
if (ret != C_KZG_OK) goto out;
out:
free(commitments);
free(polys);
return ret;
}
/**
* Computes the aggregate KZG proof for multiple blobs.
*
* @param[out] out `true` if the proof is valid, `false` if not
* @param[in] blobs Array of blobs to compute the aggregate proof for
* @param[in] n The number of blobs in the array
* @param[in] s The settings struct containing the commitment
* verification key (i.e. the trusted setup)
*/
C_KZG_RET verify_aggregate_kzg_proof(
bool *out,
const Blob *blobs,
const Bytes48 *commitments_bytes,
size_t n,
const Bytes48 *aggregated_proof_bytes,
C_KZG_RET verify_blob_kzg_proof(
bool *ok,
const Blob *blob,
const Bytes48 *commitment_bytes,
const Bytes48 *proof_bytes,
const KZGSettings *s
) {
C_KZG_RET ret;
g1_t *commitments = NULL;
Polynomial *polys = NULL;
Polynomial polynomial;
fr_t evaluation_challenge_fr, y_fr;
g1_t commitment_g1, proof_g1;
g1_t proof;
ret = bytes_to_kzg_proof(&proof, aggregated_proof_bytes);
ret = bytes_to_kzg_commitment(&commitment_g1, commitment_bytes);
if (ret != C_KZG_OK) return ret;
ret = blob_to_polynomial(&polynomial, blob);
if (ret != C_KZG_OK) return ret;
compute_challenge(&evaluation_challenge_fr, blob, &commitment_g1);
ret = evaluate_polynomial_in_evaluation_form(
&y_fr, &polynomial, &evaluation_challenge_fr, s
);
if (ret != C_KZG_OK) return ret;
ret = bytes_to_kzg_proof(&proof_g1, proof_bytes);
if (ret != C_KZG_OK) return ret;
return verify_kzg_proof_impl(
ok, &commitment_g1, &evaluation_challenge_fr, &y_fr, &proof_g1, s
);
}
/**
*
*
* @param[out] r_powers_out
* @param[in] commitments_g1
* @param[in] evaluation_challenges_fr
* @param[in] ys_fr
* @param[in] proofs_g1
*/
static C_KZG_RET compute_r_powers(
fr_t *r_powers_out,
const g1_t *commitments_g1,
const fr_t *evaluation_challenges_fr,
const fr_t *ys_fr,
const g1_t *proofs_g1,
size_t n
) {
C_KZG_RET ret;
uint8_t *bytes = NULL;
Bytes32 r_bytes;
fr_t r;
size_t input_size = 32 +
n * (BYTES_PER_COMMITMENT +
2 * BYTES_PER_FIELD_ELEMENT + BYTES_PER_PROOF);
ret = c_kzg_malloc((void **)&bytes, input_size);
if (ret != C_KZG_OK) goto out;
if (n > 0) {
ret = new_g1_array(&commitments, n);
if (ret != C_KZG_OK) goto out;
ret = c_kzg_calloc((void **)&polys, n, sizeof(Polynomial));
if (ret != C_KZG_OK) goto out;
}
/* Pointer tracking `bytes` for writing on top of it */
uint8_t *offset = bytes;
/* Copy domain separator */
memcpy(offset, RANDOM_CHALLENGE_KZG_BATCH_DOMAIN, 16);
offset += 16;
bytes_from_uint64(offset, FIELD_ELEMENTS_PER_BLOB);
offset += 8;
bytes_from_uint64(offset, n);
offset += 8;
for (size_t i = 0; i < n; i++) {
ret = bytes_to_kzg_commitment(&commitments[i], &commitments_bytes[i]);
bytes_from_g1((Bytes48 *)offset, &commitments_g1[i]);
offset += BYTES_PER_COMMITMENT;
bytes_from_bls_field((Bytes32 *)offset, &evaluation_challenges_fr[i]);
offset += BYTES_PER_FIELD_ELEMENT;
bytes_from_bls_field((Bytes32 *)offset, &ys_fr[i]);
offset += BYTES_PER_FIELD_ELEMENT;
bytes_from_g1((Bytes48 *)offset, &proofs_g1[i]);
offset += BYTES_PER_PROOF;
}
/* Now let's create the challenge! */
blst_sha256(r_bytes.bytes, bytes, input_size);
hash_to_bls_field(&r, &r_bytes);
compute_powers(r_powers_out, &r, n);
/* Make sure we wrote the entire buffer */
assert(offset == bytes + input_size);
ret = C_KZG_OK;
out:
free(bytes);
return ret;
}
/**
* Helper function for verify_blob_kzg_proof_batch(): actually perform the
* verification.
*
* @remark This function assumes that `n` is trusted and that all input arrays
* contain `n` elements. `n` should be the actual size of the arrays and not
* read off a length field in the protocol.
*
* @remark This function only works for `n > 0`.
*
* @param[out] ok `true` if the proofs are valid,
* `false` if not
* @param[in] commitments_g1 Array of commitments to verify
* @param[in] evaluation_challenges_fr Array of evaluation of points for the
* KZG proofs
* @param[in] ys_fr Array of evaluation results for the
* KZG proofs
* @param[in] proofs_g1 Array of proofs used for verification
* @param[in] n The number of
* blobs/commitments/proofs in the
* arrays
* @param[in] s The settings struct containing the
* commitment verification key (i.e. the
* trusted setup)
*/
static C_KZG_RET verify_kzg_proof_batch(
bool *ok,
const g1_t *commitments_g1,
const fr_t *evaluation_challenges_fr,
const fr_t *ys_fr,
const g1_t *proofs_g1,
size_t n,
const KZGSettings *s
) {
C_KZG_RET ret;
g1_t proof_lincomb, proof_z_lincomb, C_minus_y_lincomb, rhs_g1;
fr_t *r_powers = NULL;
g1_t *C_minus_y = NULL;
fr_t *r_times_z = NULL;
assert(n > 0);
/* First let's allocate our arrays */
ret = new_fr_array(&r_powers, n);
if (ret != C_KZG_OK) goto out;
ret = new_g1_array(&C_minus_y, n);
if (ret != C_KZG_OK) goto out;
ret = new_fr_array(&r_times_z, n);
if (ret != C_KZG_OK) goto out;
/* Compute the random lincomb challenges */
ret = compute_r_powers(
r_powers, commitments_g1, evaluation_challenges_fr, ys_fr, proofs_g1, n
);
if (ret != C_KZG_OK) goto out;
/* Compute \sum r^i * Proof_i */
ret = g1_lincomb(&proof_lincomb, proofs_g1, r_powers, n);
if (ret != C_KZG_OK) goto out;
for (size_t i = 0; i < n; i++) {
g1_t ys_encrypted;
/* Get [y_i] */
g1_mul(&ys_encrypted, &G1_GENERATOR, &ys_fr[i]);
/* Get C_i - [y_i] */
g1_sub(&C_minus_y[i], &commitments_g1[i], &ys_encrypted);
/* Get r^i * z_i */
blst_fr_mul(&r_times_z[i], &r_powers[i], &evaluation_challenges_fr[i]);
}
/* Get \sum r^i z_i Proof_i */
ret = g1_lincomb(&proof_z_lincomb, proofs_g1, r_times_z, n);
if (ret != C_KZG_OK) goto out;
/* Get \sum r^i (C_i - [y_i]) */
ret = g1_lincomb(&C_minus_y_lincomb, C_minus_y, r_powers, n);
if (ret != C_KZG_OK) goto out;
/* Get C_minus_y_lincomb + proof_z_lincomb */
blst_p1_add_or_double(&rhs_g1, &C_minus_y_lincomb, &proof_z_lincomb);
/* Do the pairing check! */
*ok = pairings_verify(
&proof_lincomb, &s->g2_values[1], &rhs_g1, &G2_GENERATOR
);
ret = C_KZG_OK;
out:
free(r_powers);
free(C_minus_y);
free(r_times_z);
return ret;
}
/**
* Given a list of blobs and blob KZG proofs, verify that they correspond to the
* provided commitments.
*
* @remark This function assumes that `n` is trusted and that all input arrays
* contain `n` elements. `n` should be the actual size of the arrays and not
* read off a length field in the protocol.
*
* @remark This function accepts if called with `n==0`.
*
* @param[out] ok `true` if the proofs are valid, `false` if not
* @param[in] blobs Array of blobs to verify
* @param[in] commitments_bytes Array of commitments to verify
* @param[in] proofs_bytes Array of proofs used for verification
* @param[in] n The number of blobs/commitments/proofs in the
* arrays
* @param[in] s The settings struct containing the commitment
* verification key (i.e. the trusted setup)
*/
C_KZG_RET verify_blob_kzg_proof_batch(
bool *ok,
const Blob *blobs,
const Bytes48 *commitments_bytes,
const Bytes48 *proofs_bytes,
size_t n,
const KZGSettings *s
) {
C_KZG_RET ret;
g1_t *commitments_g1 = NULL;
g1_t *proofs_g1 = NULL;
fr_t *evaluation_challenges_fr = NULL;
fr_t *ys_fr = NULL;
Polynomial *polynomials = NULL;
/* Exit early if we are given zero blobs */
if (n == 0) {
*ok = true;
return C_KZG_OK;
}
/* We will need a bunch of arrays to store our objects... */
ret = new_g1_array(&commitments_g1, n);
if (ret != C_KZG_OK) goto out;
ret = new_g1_array(&proofs_g1, n);
if (ret != C_KZG_OK) goto out;
ret = new_fr_array(&evaluation_challenges_fr, n);
if (ret != C_KZG_OK) goto out;
ret = new_fr_array(&ys_fr, n);
if (ret != C_KZG_OK) goto out;
ret = c_kzg_calloc((void **)&polynomials, n, sizeof(Polynomial));
if (ret != C_KZG_OK) goto out;
for (size_t i = 0; i < n; i++) {
ret = bytes_to_kzg_commitment(
&commitments_g1[i], &commitments_bytes[i]
);
if (ret != C_KZG_OK) goto out;
ret = blob_to_polynomial(&polys[i], &blobs[i]);
ret = blob_to_polynomial(&polynomials[i], &blobs[i]);
if (ret != C_KZG_OK) goto out;
compute_challenge(
&evaluation_challenges_fr[i], &blobs[i], &commitments_g1[i]
);
ret = evaluate_polynomial_in_evaluation_form(
&ys_fr[i], &polynomials[i], &evaluation_challenges_fr[i], s
);
if (ret != C_KZG_OK) goto out;
ret = bytes_to_kzg_proof(&proofs_g1[i], &proofs_bytes[i]);
if (ret != C_KZG_OK) goto out;
}
Polynomial aggregated_poly;
g1_t aggregated_poly_commitment;
fr_t evaluation_challenge;
ret = compute_aggregated_poly_and_commitment(
&aggregated_poly,
&aggregated_poly_commitment,
&evaluation_challenge,
polys,
commitments,
n
);
if (ret != C_KZG_OK) goto out;
fr_t y;
ret = evaluate_polynomial_in_evaluation_form(
&y, &aggregated_poly, &evaluation_challenge, s
);
if (ret != C_KZG_OK) goto out;
ret = verify_kzg_proof_impl(
out, &aggregated_poly_commitment, &evaluation_challenge, &y, &proof, s
ret = verify_kzg_proof_batch(
ok, commitments_g1, evaluation_challenges_fr, ys_fr, proofs_g1, n, s
);
out:
free(commitments);
free(polys);
free(commitments_g1);
free(proofs_g1);
free(evaluation_challenges_fr);
free(ys_fr);
free(polynomials);
return ret;
}

View File

@ -144,32 +144,10 @@ C_KZG_RET load_trusted_setup_file(KZGSettings *out, FILE *in);
void free_trusted_setup(KZGSettings *s);
C_KZG_RET compute_aggregate_kzg_proof(
KZGProof *out, const Blob *blobs, size_t n, const KZGSettings *s
);
C_KZG_RET verify_aggregate_kzg_proof(
bool *out,
const Blob *blobs,
const Bytes48 *commitments_bytes,
size_t n,
const Bytes48 *aggregated_proof_bytes,
const KZGSettings *s
);
C_KZG_RET blob_to_kzg_commitment(
KZGCommitment *out, const Blob *blob, const KZGSettings *s
);
C_KZG_RET verify_kzg_proof(
bool *out,
const Bytes48 *commitment_bytes,
const Bytes32 *z_bytes,
const Bytes32 *y_bytes,
const Bytes48 *proof_bytes,
const KZGSettings *s
);
C_KZG_RET compute_kzg_proof(
KZGProof *out,
const Blob *blob,
@ -177,6 +155,36 @@ C_KZG_RET compute_kzg_proof(
const KZGSettings *s
);
C_KZG_RET compute_blob_kzg_proof(
KZGProof *out, const Blob *blob, const KZGSettings *s
);
C_KZG_RET verify_kzg_proof(
bool *ok,
const Bytes48 *commitment_bytes,
const Bytes32 *z_bytes,
const Bytes32 *y_bytes,
const Bytes48 *proof_bytes,
const KZGSettings *s
);
C_KZG_RET verify_blob_kzg_proof(
bool *ok,
const Blob *blob,
const Bytes48 *commitment_bytes,
const Bytes48 *proof_bytes,
const KZGSettings *s
);
C_KZG_RET verify_blob_kzg_proof_batch(
bool *ok,
const Blob *blobs,
const Bytes48 *commitments_bytes,
const Bytes48 *proofs_bytes,
size_t n,
const KZGSettings *s
);
#ifdef __cplusplus
}
#endif

View File

@ -643,7 +643,7 @@ static void test_compute_and_verify_kzg_proof__succeeds_round_trip(void) {
/* Finally verify the proof */
ret = verify_kzg_proof(&ok, &c, &z, &y, &proof, &s);
ASSERT_EQUALS(ret, C_KZG_OK);
ASSERT_EQUALS(ok, 1);
ASSERT_EQUALS(ok, true);
}
static void test_compute_and_verify_kzg_proof__succeeds_within_domain(void) {
@ -684,10 +684,95 @@ static void test_compute_and_verify_kzg_proof__succeeds_within_domain(void) {
/* Finally verify the proof */
ret = verify_kzg_proof(&ok, &c, &z, &y, &proof, &s);
ASSERT_EQUALS(ret, C_KZG_OK);
ASSERT_EQUALS(ok, 1);
ASSERT_EQUALS(ok, true);
}
}
///////////////////////////////////////////////////////////////////////////////
// Tests for compute_blob_kzg_proof
///////////////////////////////////////////////////////////////////////////////
static void test_compute_and_verify_blob_kzg_proof__succeeds_round_trip(void) {
C_KZG_RET ret;
Bytes48 proof;
KZGCommitment c;
Blob blob;
bool ok;
/* Some preparation */
get_rand_blob(&blob);
ret = blob_to_kzg_commitment(&c, &blob, &s);
ASSERT_EQUALS(ret, C_KZG_OK);
/* Compute the proof */
ret = compute_blob_kzg_proof(&proof, &blob, &s);
ASSERT_EQUALS(ret, C_KZG_OK);
/* Finally verify the proof */
ret = verify_blob_kzg_proof(&ok, &blob, &c, &proof, &s);
ASSERT_EQUALS(ret, C_KZG_OK);
ASSERT_EQUALS(ok, true);
}
///////////////////////////////////////////////////////////////////////////////
// Tests for verify_kzg_proof_batch
///////////////////////////////////////////////////////////////////////////////
static void test_verify_kzg_proof_batch__succeeds_round_trip(void) {
C_KZG_RET ret;
const int n_samples = 16;
Bytes48 proofs[n_samples];
KZGCommitment commitments[n_samples];
Blob blobs[n_samples];
bool ok;
/* Some preparation */
for (int i = 0; i < n_samples; i++) {
get_rand_blob(&blobs[i]);
ret = blob_to_kzg_commitment(&commitments[i], &blobs[i], &s);
ASSERT_EQUALS(ret, C_KZG_OK);
ret = compute_blob_kzg_proof(&proofs[i], &blobs[i], &s);
ASSERT_EQUALS(ret, C_KZG_OK);
}
/* Verify batched proofs for 0,1,2..16 blobs */
/* This should still work with zero blobs */
for (int count = 0; count <= 16; count++) {
ret = verify_blob_kzg_proof_batch(
&ok, blobs, commitments, proofs, count, &s
);
ASSERT_EQUALS(ret, C_KZG_OK);
ASSERT_EQUALS(ok, true);
}
}
static void test_verify_kzg_proof_batch__fails_with_incorrect_proof(void) {
C_KZG_RET ret;
const int n_samples = 2;
Bytes48 proofs[n_samples];
KZGCommitment commitments[n_samples];
Blob blobs[n_samples];
bool ok;
/* Some preparation */
for (int i = 0; i < n_samples; i++) {
get_rand_blob(&blobs[i]);
ret = blob_to_kzg_commitment(&commitments[i], &blobs[i], &s);
ASSERT_EQUALS(ret, C_KZG_OK);
ret = compute_blob_kzg_proof(&proofs[i], &blobs[i], &s);
ASSERT_EQUALS(ret, C_KZG_OK);
}
/* Overwrite second proof with an incorrect one */
proofs[1] = proofs[0];
ret = verify_blob_kzg_proof_batch(
&ok, blobs, commitments, proofs, n_samples, &s
);
ASSERT_EQUALS(ret, C_KZG_OK);
ASSERT_EQUALS(ok, false);
}
///////////////////////////////////////////////////////////////////////////////
// Profiling Functions
///////////////////////////////////////////////////////////////////////////////
@ -833,6 +918,9 @@ int main(void) {
RUN(test_compute_kzg_proof__succeeds_expected_proof);
RUN(test_compute_and_verify_kzg_proof__succeeds_round_trip);
RUN(test_compute_and_verify_kzg_proof__succeeds_within_domain);
RUN(test_compute_and_verify_blob_kzg_proof__succeeds_round_trip);
RUN(test_verify_kzg_proof_batch__succeeds_round_trip);
RUN(test_verify_kzg_proof_batch__fails_with_incorrect_proof);
/*
* These functions are only executed if we're profiling. To me, it makes