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:
parent
f87eee57d3
commit
46d529cf00
|
@ -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:
|
||||
|
||||
|
|
539
src/c_kzg_4844.c
539
src/c_kzg_4844.c
|
@ -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]);
|
||||
/* 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)
|
||||
*/
|
||||
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[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 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);
|
||||
if (ret != C_KZG_OK) goto out;
|
||||
ret = bytes_to_kzg_commitment(&commitment_g1, commitment_bytes);
|
||||
if (ret != C_KZG_OK) return ret;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
/* 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 = blob_to_polynomial(&polys[i], &blobs[i]);
|
||||
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(&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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue