From 8907fbcfe2573fc282ab1d35dd63b697e9035efe Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Tue, 24 Jan 2023 19:23:42 +0100 Subject: [PATCH] Expose `compute_kzg_proof` (#80) * Expose computeKzgProof * Revert changes to bytes_to/from_bls_field * Update comments * Revert changes to bytes_from_bls_field * Revert change to parameter name * Add compute_kzg_proof to readme * Refactor in support of asn's PR * Clean up a little * Fix param name doc * Introduce Bytes32 type * Update bindings * Replaces bytes with b to match spec --- README.md | 5 +- bindings/csharp/ckzg.c | 2 +- bindings/csharp/ckzg.h | 2 +- bindings/java/c_kzg_4844_jni.c | 4 +- bindings/node.js/kzg.cxx | 6 +-- bindings/node.js/kzg.ts | 10 ++-- bindings/rust/src/bindings.rs | 12 ++--- bindings/rust/src/lib.rs | 8 +-- src/c_kzg_4844.c | 96 ++++++++++++++++++++++------------ src/c_kzg_4844.h | 11 ++-- 10 files changed, 96 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index f4424ff..e80ca87 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,11 @@ This is a copy of [C-KZG](https://github.com/benjaminion/c-kzg) stripped-down to support the [Polynomial Commitments](https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/polynomial-commitments.md) API: -- `compute_aggregate_kzg_proof` -- `verify_aggregate_kzg_proof` - `blob_to_kzg_commitment` +- `compute_kzg_proof` +- `compute_aggregate_kzg_proof` - `verify_kzg_proof` +- `verify_aggregate_kzg_proof` We also provide functions for loading/freeing the trusted setup: diff --git a/bindings/csharp/ckzg.c b/bindings/csharp/ckzg.c index c03c588..af5968c 100644 --- a/bindings/csharp/ckzg.c +++ b/bindings/csharp/ckzg.c @@ -32,7 +32,7 @@ int verify_aggregate_kzg_proof_wrap(const Blob *blobs, const KZGCommitment *comm return b ? 0 : 1; } -int verify_kzg_proof_wrap(const KZGCommitment *c, const BLSFieldElement *z, const BLSFieldElement *y, const KZGProof *p, KZGSettings *s) { +int verify_kzg_proof_wrap(const KZGCommitment *c, const Bytes32 *z, const Bytes32 *y, const KZGProof *p, KZGSettings *s) { bool out; if (verify_kzg_proof(&out, c, z, y, p, s) != C_KZG_OK) return -2; diff --git a/bindings/csharp/ckzg.h b/bindings/csharp/ckzg.h index 90164ee..c27f61d 100644 --- a/bindings/csharp/ckzg.h +++ b/bindings/csharp/ckzg.h @@ -19,4 +19,4 @@ DLLEXPORT int verify_aggregate_kzg_proof_wrap(const Blob blobs[], const KZGCommi DLLEXPORT C_KZG_RET compute_aggregate_kzg_proof(KZGProof *out, const Blob blobs[], size_t n, const KZGSettings *s); -DLLEXPORT int verify_kzg_proof_wrap(const KZGCommitment *c, const BLSFieldElement *z, const BLSFieldElement *y, const KZGProof *p, KZGSettings *s); +DLLEXPORT int verify_kzg_proof_wrap(const KZGCommitment *c, const Bytes32 *z, const Bytes32 *y, const KZGProof *p, KZGSettings *s); diff --git a/bindings/java/c_kzg_4844_jni.c b/bindings/java/c_kzg_4844_jni.c index d4b7b87..9c3bb54 100644 --- a/bindings/java/c_kzg_4844_jni.c +++ b/bindings/java/c_kzg_4844_jni.c @@ -249,8 +249,8 @@ JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_verifyKzgProof(JNI KZGCommitment *commitment_native = (KZGCommitment *)(*env)->GetByteArrayElements(env, commitment, NULL); KZGProof *proof_native = (KZGProof *)(*env)->GetByteArrayElements(env, proof, NULL); - BLSFieldElement *z_native = (BLSFieldElement *)(*env)->GetByteArrayElements(env, z, NULL); - BLSFieldElement *y_native = (BLSFieldElement *)(*env)->GetByteArrayElements(env, y, NULL); + Bytes32 *z_native = (Bytes32 *)(*env)->GetByteArrayElements(env, z, NULL); + Bytes32 *y_native = (Bytes32 *)(*env)->GetByteArrayElements(env, y, NULL); bool out; C_KZG_RET ret = verify_kzg_proof(&out, commitment_native, z_native, y_native, proof_native, settings); diff --git a/bindings/node.js/kzg.cxx b/bindings/node.js/kzg.cxx index 69dae67..020fd5c 100644 --- a/bindings/node.js/kzg.cxx +++ b/bindings/node.js/kzg.cxx @@ -266,7 +266,7 @@ Napi::Value VerifyAggregateKzgProof(const Napi::CallbackInfo& info) { return Napi::Boolean::New(env, verification_result); } -// verifyKzgProof: (polynomialKzg: KZGCommitment, z: BLSFieldElement, y: BLSFieldElement, kzgProof: KZGProof, setupHandle: SetupHandle) => boolean; +// verifyKzgProof: (polynomialKzg: KZGCommitment, z: Bytes32, y: Bytes32, kzgProof: KZGProof, setupHandle: SetupHandle) => boolean; Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) { auto env = info.Env(); @@ -290,8 +290,8 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) { C_KZG_RET ret = verify_kzg_proof( &out, (KZGCommitment *)polynomial_kzg, - (BLSFieldElement *)z, - (BLSFieldElement *)y, + (Bytes32 *)z, + (Bytes32 *)y, (KZGProof *)kzg_proof, kzg_settings ); diff --git a/bindings/node.js/kzg.ts b/bindings/node.js/kzg.ts index 5043954..45b9567 100644 --- a/bindings/node.js/kzg.ts +++ b/bindings/node.js/kzg.ts @@ -5,7 +5,7 @@ const kzg: KZG = require("./kzg.node"); const fs = require("fs"); -export type BLSFieldElement = Uint8Array; // 32 bytes +export type Bytes32 = Uint8Array; // 32 bytes export type KZGProof = Uint8Array; // 48 bytes export type KZGCommitment = Uint8Array; // 48 bytes export type Blob = Uint8Array; // 4096 * 32 bytes @@ -37,8 +37,8 @@ type KZG = { verifyKzgProof: ( polynomialKzg: KZGCommitment, - z: BLSFieldElement, - y: BLSFieldElement, + z: Bytes32, + y: Bytes32, kzgProof: KZGProof, setupHandle: SetupHandle, ) => boolean; @@ -115,8 +115,8 @@ export function computeAggregateKzgProof(blobs: Blob[]): KZGProof { export function verifyKzgProof( polynomialKzg: KZGCommitment, - z: BLSFieldElement, - y: BLSFieldElement, + z: Bytes32, + y: Bytes32, kzgProof: KZGProof, ): boolean { return kzg.verifyKzgProof( diff --git a/bindings/rust/src/bindings.rs b/bindings/rust/src/bindings.rs index a62bd53..54e2c23 100644 --- a/bindings/rust/src/bindings.rs +++ b/bindings/rust/src/bindings.rs @@ -79,12 +79,12 @@ struct blst_p2_affine { #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct BLSFieldElement { - bytes: [u8; BYTES_PER_FIELD_ELEMENT], +pub struct Bytes32 { + bytes: [u8; 32], } -impl Deref for BLSFieldElement { - type Target = [u8; BYTES_PER_FIELD_ELEMENT]; +impl Deref for Bytes32 { + type Target = [u8; 32]; fn deref(&self) -> &Self::Target { &self.bytes } @@ -222,8 +222,8 @@ extern "C" { pub fn verify_kzg_proof( out: *mut bool, polynomial_kzg: *const KZGCommitment, - z: *const BLSFieldElement, - y: *const BLSFieldElement, + z: *const Bytes32, + y: *const Bytes32, kzg_proof: *const KZGProof, s: *const KZGSettings, ) -> C_KZG_RET; diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index b8621e5..8dff105 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -181,8 +181,8 @@ impl KZGProof { pub fn verify_kzg_proof( &self, kzg_commitment: KZGCommitment, - z: BLSFieldElement, - y: BLSFieldElement, + z: Bytes32, + y: Bytes32, kzg_settings: &KZGSettings, ) -> Result { let mut verified: MaybeUninit = MaybeUninit::uninit(); @@ -257,8 +257,8 @@ impl From<[u8; BYTES_PER_BLOB]> for Blob { } } -impl From<[u8; BYTES_PER_FIELD_ELEMENT]> for BLSFieldElement { - fn from(value: [u8; BYTES_PER_FIELD_ELEMENT]) -> Self { +impl From<[u8; 32]> for Bytes32 { + fn from(value: [u8; 32]) -> Self { Self { bytes: value } } } diff --git a/src/c_kzg_4844.c b/src/c_kzg_4844.c index eaa2c9e..4319958 100644 --- a/src/c_kzg_4844.c +++ b/src/c_kzg_4844.c @@ -642,13 +642,12 @@ static C_KZG_RET bit_reversal_permutation(void *values, size_t size, uint64_t n) * @param[out] out The field element to store the result * @param[in] bytes A 32-byte array containing the input */ -static void hash_to_bls_field(fr_t *out, const uint8_t bytes[32]) { +static void hash_to_bls_field(fr_t *out, const Bytes32 *b) { blst_scalar tmp; - blst_scalar_from_lendian(&tmp, bytes); + blst_scalar_from_lendian(&tmp, b->bytes); blst_fr_from_scalar(out, &tmp); } - /** * Deserialize bytes into a BLS field element. * @@ -657,9 +656,9 @@ static void hash_to_bls_field(fr_t *out, const uint8_t bytes[32]) { * @retval C_KZG_OK Deserialization successful * @retval C_KZG_BADARGS Input was not a valid scalar field element */ -static C_KZG_RET bytes_to_bls_field(fr_t *out, const uint8_t bytes[32]) { +static C_KZG_RET bytes_to_bls_field(fr_t *out, const Bytes32 *b) { blst_scalar tmp; - blst_scalar_from_lendian(&tmp, bytes); + blst_scalar_from_lendian(&tmp, b->bytes); if (!blst_scalar_fr_check(&tmp)) return C_KZG_BADARGS; blst_fr_from_scalar(out, &tmp); return C_KZG_OK; @@ -676,7 +675,7 @@ static C_KZG_RET bytes_to_bls_field(fr_t *out, const uint8_t bytes[32]) { static C_KZG_RET blob_to_polynomial(Polynomial *p, const Blob *blob) { C_KZG_RET ret; for (size_t i = 0; i < FIELD_ELEMENTS_PER_BLOB; i++) { - ret = bytes_to_bls_field(&p->evals[i], &blob->bytes[i * BYTES_PER_FIELD_ELEMENT]); + ret = bytes_to_bls_field(&p->evals[i], (Bytes32 *)&blob->bytes[i * BYTES_PER_FIELD_ELEMENT]); if (ret != C_KZG_OK) return ret; } return C_KZG_OK; @@ -731,21 +730,21 @@ static C_KZG_RET compute_challenges(fr_t *eval_challenge_out, fr_t *r_powers_out uint8_t hash_input[33]; /* Compute r */ - uint8_t r_bytes[32] = {0}; + Bytes32 r_bytes; memcpy(hash_input, hashed_data, 32); hash_input[32] = 0x0; - hash(r_bytes, hash_input, 33); + hash(r_bytes.bytes, hash_input, 33); /* Compute r_powers */ fr_t r; - hash_to_bls_field(&r, r_bytes); + hash_to_bls_field(&r, &r_bytes); compute_powers(r_powers_out, &r, n); /* Compute eval_challenge */ - uint8_t eval_challenge[32] = {0}; + Bytes32 eval_challenge; hash_input[32] = 0x1; - hash(eval_challenge, hash_input, 33); - hash_to_bls_field(eval_challenge_out, eval_challenge); + hash(eval_challenge.bytes, hash_input, 33); + hash_to_bls_field(eval_challenge_out, &eval_challenge); free(bytes); return C_KZG_OK; @@ -975,21 +974,21 @@ static C_KZG_RET verify_kzg_proof_impl(bool *out, const g1_t *commitment, const */ C_KZG_RET verify_kzg_proof(bool *out, const KZGCommitment *commitment, - const BLSFieldElement *z, - const BLSFieldElement *y, + const Bytes32 *z, + const Bytes32 *y, const KZGProof *kzg_proof, const KZGSettings *s) { C_KZG_RET ret; fr_t frz, fry; g1_t g1commitment, g1proof; - ret = bytes_to_g1(&g1commitment, (const uint8_t *)(commitment)); + ret = bytes_to_g1(&g1commitment, commitment->bytes); if (ret != C_KZG_OK) return ret; - ret = bytes_to_bls_field(&frz, (const uint8_t *)(z)); + ret = bytes_to_bls_field(&frz, z); if (ret != C_KZG_OK) return ret; - ret = bytes_to_bls_field(&fry, (const uint8_t *)(y)); + ret = bytes_to_bls_field(&fry, y); if (ret != C_KZG_OK) return ret; - ret = bytes_to_g1(&g1proof, (const uint8_t *)(kzg_proof)); + ret = bytes_to_g1(&g1proof, kzg_proof->bytes); if (ret != C_KZG_OK) return ret; return verify_kzg_proof_impl(out, &g1commitment, &frz, &fry, &g1proof, s); @@ -1022,23 +1021,52 @@ static C_KZG_RET verify_kzg_proof_impl(bool *out, const g1_t *commitment, const return C_KZG_OK; } +/* Forward function declaration */ +C_KZG_RET compute_kzg_proof_impl(KZGProof *out, const Polynomial *polynomial, const fr_t *z, const KZGSettings *s); + /** - * Compute KZG proof for polynomial in Lagrange form at position x. + * Compute KZG proof for polynomial in Lagrange form at position z. * - * @param[out] out The combined proof as a single G1 element - * @param[in] p The polynomial in Lagrange form - * @param[in] z The evaluation point - * @param[in] s The settings containing the secrets, previously initialised with #new_kzg_settings + * @param[out] out The combined proof as a single G1 element + * @param[in] blob The blob (polynomial) to generate a proof for + * @param[in] z The generator z-value for the evaluation points + * @param[in] s The settings containing the secrets, previously initialised with #new_kzg_settings * @retval C_KZG_OK All is well * @retval C_KZG_MALLOC Memory allocation failed */ -static C_KZG_RET compute_kzg_proof(g1_t *out, const Polynomial *p, const fr_t *z, const KZGSettings *s) { +C_KZG_RET compute_kzg_proof(KZGProof *out, const Blob *blob, const Bytes32 *z, const KZGSettings *s) { + C_KZG_RET ret; + Polynomial polynomial; + fr_t frz; + + ret = blob_to_polynomial(&polynomial, blob); + if (ret != C_KZG_OK) goto out; + ret = bytes_to_bls_field(&frz, z); + if (ret != C_KZG_OK) goto out; + ret = compute_kzg_proof_impl(out, &polynomial, &frz, s); + if (ret != C_KZG_OK) goto out; + +out: + return ret; +} + +/** + * Helper function for compute_kzg_proof() and compute_aggregate_kzg_proof(). + * + * @param[out] out The combined proof as a single G1 element + * @param[in] polynomial The polynomial in Lagrange form + * @param[in] z The evaluation point + * @param[in] s The settings containing the secrets, previously initialised with #new_kzg_settings + * @retval C_KZG_OK All is well + * @retval C_KZG_MALLOC Memory allocation failed + */ +C_KZG_RET compute_kzg_proof_impl(KZGProof *out, const Polynomial *polynomial, const fr_t *z, const KZGSettings *s) { C_KZG_RET ret; fr_t y; fr_t *inverses_in = NULL; fr_t *inverses = NULL; - ret = evaluate_polynomial_in_evaluation_form(&y, p, z, s); + ret = evaluate_polynomial_in_evaluation_form(&y, polynomial, z, s); if (ret != C_KZG_OK) goto out; fr_t tmp; @@ -1057,7 +1085,7 @@ static C_KZG_RET compute_kzg_proof(g1_t *out, const Polynomial *p, const fr_t *z continue; } // (p_i - y) / (ω_i - z) - blst_fr_sub(&q.evals[i], &p->evals[i], &y); + blst_fr_sub(&q.evals[i], &polynomial->evals[i], &y); blst_fr_sub(&inverses_in[i], &roots_of_unity[i], z); } @@ -1079,14 +1107,18 @@ static C_KZG_RET compute_kzg_proof(g1_t *out, const Polynomial *p, const fr_t *z ret = fr_batch_inv(inverses, inverses_in, FIELD_ELEMENTS_PER_BLOB); if (ret != C_KZG_OK) goto out; for (i = 0; i < FIELD_ELEMENTS_PER_BLOB; i++) { - blst_fr_sub(&tmp, &p->evals[i], &y); + blst_fr_sub(&tmp, &polynomial->evals[i], &y); blst_fr_mul(&tmp, &tmp, &roots_of_unity[i]); blst_fr_mul(&tmp, &tmp, &inverses[i]); blst_fr_add(&q.evals[m], &q.evals[m], &tmp); } } - ret = g1_lincomb(out, s->g1_values, (const fr_t *)(&q.evals), FIELD_ELEMENTS_PER_BLOB); + g1_t out_g1; + ret = g1_lincomb(&out_g1, s->g1_values, (const fr_t *)(&q.evals), FIELD_ELEMENTS_PER_BLOB); + if (ret != C_KZG_OK) goto out; + + bytes_from_g1(out->bytes, &out_g1); out: free(inverses_in); @@ -1177,10 +1209,8 @@ C_KZG_RET compute_aggregate_kzg_proof(KZGProof *out, ret = compute_aggregated_poly_and_commitment(&aggregated_poly, &aggregated_poly_commitment, &evaluation_challenge, polys, commitments, n); if (ret != C_KZG_OK) goto out; - g1_t proof; - ret = compute_kzg_proof(&proof, &aggregated_poly, &evaluation_challenge, s); + ret = compute_kzg_proof_impl(out, &aggregated_poly, &evaluation_challenge, s); if (ret != C_KZG_OK) goto out; - bytes_from_g1((uint8_t *)(out), &proof); out: free(commitments); @@ -1210,7 +1240,7 @@ C_KZG_RET verify_aggregate_kzg_proof(bool *out, Polynomial* polys = NULL; g1_t proof; - ret = bytes_to_g1(&proof, (uint8_t *)(kzg_aggregated_proof)); + ret = bytes_to_g1(&proof, kzg_aggregated_proof->bytes); if (ret != C_KZG_OK) goto out; commitments = calloc(n, sizeof(g1_t)); @@ -1226,7 +1256,7 @@ C_KZG_RET verify_aggregate_kzg_proof(bool *out, } for (size_t i = 0; i < n; i++) { - ret = bytes_to_g1(&commitments[i], (uint8_t *)(&expected_kzg_commitments[i])); + ret = bytes_to_g1(&commitments[i], expected_kzg_commitments[i].bytes); if (ret != C_KZG_OK) goto out; ret = blob_to_polynomial(&polys[i], &blobs[i]); if (ret != C_KZG_OK) goto out; diff --git a/src/c_kzg_4844.h b/src/c_kzg_4844.h index e3c390c..270ee67 100644 --- a/src/c_kzg_4844.h +++ b/src/c_kzg_4844.h @@ -44,9 +44,9 @@ typedef blst_p1 g1_t; /**< Internal G1 group element type */ typedef blst_p2 g2_t; /**< Internal G2 group element type */ typedef blst_fr fr_t; /**< Internal Fr field element type */ +typedef struct { uint8_t bytes[32]; } Bytes32; typedef struct { uint8_t bytes[BYTES_PER_COMMITMENT]; } KZGCommitment; typedef struct { uint8_t bytes[BYTES_PER_PROOF]; } KZGProof; -typedef struct { uint8_t bytes[BYTES_PER_FIELD_ELEMENT]; } BLSFieldElement; typedef struct { uint8_t bytes[BYTES_PER_BLOB]; } Blob; /** @@ -112,11 +112,16 @@ C_KZG_RET blob_to_kzg_commitment(KZGCommitment *out, C_KZG_RET verify_kzg_proof(bool *out, const KZGCommitment *polynomial_kzg, - const BLSFieldElement *z, - const BLSFieldElement *y, + const Bytes32 *z, + const Bytes32 *y, const KZGProof *kzg_proof, const KZGSettings *s); +C_KZG_RET compute_kzg_proof(KZGProof *out, + const Blob *p, + const Bytes32 *z, + const KZGSettings *s); + #ifdef __cplusplus } #endif