Bytes-only interface (#62)

* Convert argument types to bytes

* Update java bindings

* Update python bindings

* Update node.js bindings

* Update c# bindings

* Fix java binding compile issues

* Fix incorrect memcpy in nodejs bindings

* Fix bug (called the wrong func)

* Fix issues with java bindings

* Fix issues with node.js bindings

* Remove unnecessary wrapped funcs for c#

* Rename struct member to bytes

* Use goto out for callocs

* Fix nit

* Make un-exported funcs static

* Fix python bindings

* Check commitment length in python bindings

* Update python error message

* Steal good ideas from #37

* Fix tests.py which didn't get copied over

* Convert remaining a[] to *a

* Add missing Py_DECREF

* Bytes only rust (#1)

* Make interface bytes only
* Fix benches
* Avoid newtypes for kzg types
* Fix benches again
* Make fields private
* tidy
* Address review comments

* Fix one small thing in rust bindings

* Use ckzg types where possible

* Remove null terminator from domain bytes in rust

* Update rust binding docs

* Use BYTES_PER_* where applicable

* Add extra check for calloc

Co-authored-by: Pawan Dhananjay <pawandhananjay@gmail.com>
This commit is contained in:
Justin Traglia 2023-01-16 14:05:23 -06:00 committed by GitHub
parent 7e3189d48a
commit 69f6155d75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 401 additions and 624 deletions

View File

@ -27,7 +27,7 @@ public class Ckzg
/// <param name="blob">Flatten array of blob elements</param>
/// <param name="ts">Trusted setup settings</param>
/// <returns>Returns error code or <c>0</c> if successful</returns>
[DllImport("ckzg", EntryPoint = "blob_to_kzg_commitment_wrap", CallingConvention = CallingConvention.Cdecl)]
[DllImport("ckzg", EntryPoint = "blob_to_kzg_commitment", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern int BlobToKzgCommitment(byte* commitment, byte* blob, IntPtr ts);
@ -39,7 +39,7 @@ public class Ckzg
/// <param name="count">Blobs count</param>
/// <param name="ts">Trusted setup settings</param>
/// <returns>Returns error code or <c>0</c> if successful</returns>
[DllImport("ckzg", EntryPoint = "compute_aggregate_kzg_proof_wrap", CallingConvention = CallingConvention.Cdecl)] // returns 0 on success
[DllImport("ckzg", EntryPoint = "compute_aggregate_kzg_proof", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern int ComputeAggregatedKzgProof(byte* proof, byte* blobs, int count, IntPtr ts);
@ -52,7 +52,7 @@ public class Ckzg
/// <param name="proof"></param>
/// <param name="ts">Trusted setup settings</param>
/// <returns>Returns error code or <c>0</c> if the proof is correct</returns>
[DllImport("ckzg", EntryPoint = "verify_aggregate_kzg_proof_wrap", CallingConvention = CallingConvention.Cdecl)] // returns 0 on success
[DllImport("ckzg", EntryPoint = "verify_aggregate_kzg_proof_wrap", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern int VerifyAggregatedKzgProof(byte* blobs, byte* commitments, int count, byte* proof, IntPtr ts);
/// <summary>
@ -64,7 +64,7 @@ public class Ckzg
/// <param name="proof">Proof</param>
/// <param name="ts">Trusted setup settings</param>
/// <returns>Returns error code or <c>0</c> if the proof is correct</returns>
[DllImport("ckzg", EntryPoint = "verify_kzg_proof_wrap", CallingConvention = CallingConvention.Cdecl)] // returns 0 on success
[DllImport("ckzg", EntryPoint = "verify_kzg_proof_wrap", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern int VerifyKzgProof(byte* commitment, byte* z, byte* y, byte* proof, IntPtr ts);
/// <summary>

View File

@ -24,55 +24,17 @@ void free_trusted_setup_wrap(KZGSettings *s) {
free(s);
}
C_KZG_RET blob_to_kzg_commitment_wrap(uint8_t out[48], const Blob *blob, const KZGSettings *s) {
KZGCommitment c;
C_KZG_RET ret;
ret = blob_to_kzg_commitment(&c, blob, s);
if (ret != C_KZG_OK) return ret;
bytes_from_g1(out, &c);
return C_KZG_OK;
}
int verify_aggregate_kzg_proof_wrap(const Blob blobs[], const uint8_t commitments[], size_t n, const uint8_t proof[48], const KZGSettings *s) {
KZGProof f;
C_KZG_RET ret;
ret = bytes_to_g1(&f, proof);
if (ret != C_KZG_OK) return -1;
KZGCommitment* c = calloc(n, sizeof(KZGCommitment));
if (c == NULL) return -2;
for (size_t i = 0; i < n; i++) {
ret = bytes_to_g1(&c[i], &commitments[i * 48]);
if (ret != C_KZG_OK) { free(c); return -1; }
}
int verify_aggregate_kzg_proof_wrap(const Blob *blobs, const KZGCommitment *commitments, size_t n, const KZGProof *proof, const KZGSettings *s) {
bool b;
ret = verify_aggregate_kzg_proof(&b, blobs, c, n, &f, s);
free(c);
C_KZG_RET ret = verify_aggregate_kzg_proof(&b, blobs, commitments, n, proof, s);
if (ret != C_KZG_OK) return -1;
return b ? 0 : 1;
}
C_KZG_RET compute_aggregate_kzg_proof_wrap(uint8_t out[48], const Blob blobs[], size_t n, const KZGSettings *s) {
KZGProof f;
C_KZG_RET ret;
ret = compute_aggregate_kzg_proof(&f, blobs, n, s);
if (ret != C_KZG_OK) return ret;
bytes_from_g1(out, &f);
return C_KZG_OK;
}
int verify_kzg_proof_wrap(const uint8_t c[48], const uint8_t z[32], const uint8_t y[32], const uint8_t p[48], KZGSettings *s) {
KZGCommitment commitment;
KZGProof proof;
int verify_kzg_proof_wrap(const KZGCommitment *c, const BLSFieldElement *z, const BLSFieldElement *y, const KZGProof *p, KZGSettings *s) {
bool out;
if (bytes_to_g1(&commitment, c) != C_KZG_OK) return -1;
if (bytes_to_g1(&proof, p) != C_KZG_OK) return -1;
if (verify_kzg_proof(&out, &commitment, z, y, &proof, s) != C_KZG_OK)
if (verify_kzg_proof(&out, c, z, y, p, s) != C_KZG_OK)
return -2;
return out ? 0 : 1;

View File

@ -13,10 +13,10 @@ DLLEXPORT KZGSettings* load_trusted_setup_wrap(const char* file);
DLLEXPORT void free_trusted_setup_wrap(KZGSettings *s);
DLLEXPORT C_KZG_RET blob_to_kzg_commitment_wrap(uint8_t out[48], const Blob *blob, const KZGSettings *s);
DLLEXPORT C_KZG_RET blob_to_kzg_commitment(KZGCommitment *out, const Blob *blob, const KZGSettings *s);
DLLEXPORT int verify_aggregate_kzg_proof_wrap(const Blob blobs[], const uint8_t commitments[], size_t n, const uint8_t proof[48], const KZGSettings *s);
DLLEXPORT int verify_aggregate_kzg_proof_wrap(const Blob blobs[], const KZGCommitment *commitments, size_t n, const KZGProof *proof, const KZGSettings *s);
DLLEXPORT C_KZG_RET compute_aggregate_kzg_proof_wrap(uint8_t out[48], const Blob blobs[], size_t n, const KZGSettings *s);
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 uint8_t c[48], const uint8_t z[32], const uint8_t y[32], const uint8_t p[48], KZGSettings *s);
DLLEXPORT int verify_kzg_proof_wrap(const KZGCommitment *c, const BLSFieldElement *z, const BLSFieldElement *y, const KZGProof *p, KZGSettings *s);

View File

@ -15,18 +15,18 @@ void calculate_proof_and_commitment(char * trusted_setup_path){
blob[n] = i % 250;
n++;
}
int res0 = compute_aggregate_kzg_proof_wrap(proof, blob, 1, s);
int res1 = blob_to_kzg_commitment_wrap(commitment, blob, s);
int res0 = compute_aggregate_kzg_proof(proof, blob, 1, s);
int res1 = blob_to_kzg_commitment(commitment, blob, s);
FILE *f = fopen("output.txt", "wt");
// commitment
for(int i = 0; i< 48; i++){
for(int i = 0; i < 48; i++){
fprintf(f, "%02x", commitment[i]);
}
fprintf(f, "\n");
// proof
for(int i = 0; i< 48; i++){
for(int i = 0; i < 48; i++){
fprintf(f, "%02x", proof[i]);
}
fprintf(f, "\n");

View File

@ -58,13 +58,16 @@ endif
all: build test benchmark
.PHONY: build
build:
mkdir -p ${LIBRARY_FOLDER}
${CLANG_EXECUTABLE} ${CC_FLAGS} ${CLANG_FLAGS} ${OPTIMIZATION_LEVEL} -Wall -Wno-missing-braces ${addprefix -I,${INCLUDE_DIRS}} -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/${JNI_INCLUDE_FOLDER}" -DFIELD_ELEMENTS_PER_BLOB=${FIELD_ELEMENTS_PER_BLOB} -o ${LIBRARY_FOLDER}/${LIBRARY_RESOURCE} ${TARGETS}
.PHONY: test
test:
${GRADLE_COMMAND} clean test
.PHONY: benchmark
benchmark:
${GRADLE_COMMAND} clean jmh

View File

@ -141,13 +141,15 @@ JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_computeAggregate
return NULL;
}
size_t count_native = (size_t)count;
jbyte *blobs_native = (*env)->GetByteArrayElements(env, blobs, NULL);
jbyteArray proof = (*env)->NewByteArray(env, BYTES_PER_PROOF);
KZGProof *proof_native = (KZGProof *)(uint8_t *)(*env)->GetByteArrayElements(env, proof, NULL);
KZGProof p;
C_KZG_RET ret = compute_aggregate_kzg_proof(&p, (const Blob *)blobs_native, (size_t)count, settings);
C_KZG_RET ret = compute_aggregate_kzg_proof(proof_native, (const Blob *)blobs_native, count_native, settings);
(*env)->ReleaseByteArrayElements(env, blobs, blobs_native, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, proof, (jbyte *)proof_native, 0);
if (ret != C_KZG_OK)
{
@ -155,13 +157,6 @@ JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_computeAggregate
return NULL;
}
jbyteArray proof = (*env)->NewByteArray(env, BYTES_PER_PROOF);
uint8_t *out = (uint8_t *)(*env)->GetByteArrayElements(env, proof, 0);
bytes_from_g1(out, &p);
(*env)->ReleaseByteArrayElements(env, proof, (jbyte *)out, 0);
return proof;
}
@ -182,50 +177,16 @@ JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_verifyAggregateKzg
}
size_t count_native = (size_t)count;
jbyte *proof_native = (*env)->GetByteArrayElements(env, proof, NULL);
KZGProof f;
C_KZG_RET ret;
ret = bytes_to_g1(&f, (uint8_t *)proof_native);
(*env)->ReleaseByteArrayElements(env, proof, proof_native, JNI_ABORT);
if (ret != C_KZG_OK)
{
throw_c_kzg_exception(env, ret, "There was an error while converting proof to g1.");
return 0;
}
KZGCommitment *c = calloc(count_native, sizeof(KZGCommitment));
uint8_t *commitments_native = (uint8_t *)(*env)->GetByteArrayElements(env, commitments, NULL);
for (size_t i = 0; i < count_native; i++)
{
ret = bytes_to_g1(&c[i], &commitments_native[i * BYTES_PER_COMMITMENT]);
if (ret != C_KZG_OK)
{
(*env)->ReleaseByteArrayElements(env, commitments, (jbyte *)commitments_native, JNI_ABORT);
free(c);
char arr[100];
sprintf(arr, "There was an error while converting commitment (%zu/%zu) to g1.", i + 1, count_native);
throw_c_kzg_exception(env, ret, arr);
return 0;
}
}
(*env)->ReleaseByteArrayElements(env, commitments, (jbyte *)commitments_native, JNI_ABORT);
KZGProof *proof_native = (KZGProof *)(*env)->GetByteArrayElements(env, proof, NULL);
KZGCommitment *commitments_native = (KZGCommitment *)(*env)->GetByteArrayElements(env, commitments, NULL);
jbyte *blobs_native = (*env)->GetByteArrayElements(env, blobs, NULL);
bool out;
ret = verify_aggregate_kzg_proof(&out, (const Blob *)blobs_native, c, count_native, &f, settings);
C_KZG_RET ret = verify_aggregate_kzg_proof(&out, (const Blob *)blobs_native, commitments_native, count_native, proof_native, settings);
(*env)->ReleaseByteArrayElements(env, proof, (jbyte *)proof_native, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, commitments, (jbyte *)commitments_native, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, blobs, blobs_native, JNI_ABORT);
free(c);
if (ret != C_KZG_OK)
{
@ -252,13 +213,13 @@ JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_blobToKzgCommitm
}
jbyte *blob_native = (*env)->GetByteArrayElements(env, blob, NULL);
jbyteArray commitment = (*env)->NewByteArray(env, BYTES_PER_COMMITMENT);
KZGCommitment *commitment_native = (KZGCommitment *)(*env)->GetByteArrayElements(env, commitment, NULL);
KZGCommitment c;
C_KZG_RET ret;
ret = blob_to_kzg_commitment(&c, (const Blob *)blob_native, settings);
C_KZG_RET ret = blob_to_kzg_commitment(commitment_native, (const Blob *)blob_native, settings);
(*env)->ReleaseByteArrayElements(env, blob, blob_native, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, commitment, (jbyte *)commitment_native, 0);
if (ret != C_KZG_OK)
{
@ -266,13 +227,6 @@ JNIEXPORT jbyteArray JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_blobToKzgCommitm
return NULL;
}
jbyteArray commitment = (*env)->NewByteArray(env, BYTES_PER_COMMITMENT);
uint8_t *out = (uint8_t *)(*env)->GetByteArrayElements(env, commitment, 0);
bytes_from_g1(out, &c);
(*env)->ReleaseByteArrayElements(env, commitment, (jbyte *)out, 0);
return commitment;
}
@ -284,45 +238,18 @@ JNIEXPORT jboolean JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_verifyKzgProof(JNI
return 0;
}
C_KZG_RET ret;
KZGCommitment c;
jbyte *commitment_native = (*env)->GetByteArrayElements(env, commitment, NULL);
ret = bytes_to_g1(&c, (uint8_t *)commitment_native);
(*env)->ReleaseByteArrayElements(env, commitment, commitment_native, JNI_ABORT);
if (ret != C_KZG_OK)
{
throw_c_kzg_exception(env, ret, "There was an error while converting commitment to g1.");
return 0;
}
KZGProof p;
jbyte *proof_native = (*env)->GetByteArrayElements(env, proof, NULL);
ret = bytes_to_g1(&p, (uint8_t *)proof_native);
(*env)->ReleaseByteArrayElements(env, proof, proof_native, JNI_ABORT);
if (ret != C_KZG_OK)
{
throw_c_kzg_exception(env, ret, "There was an error while converting proof to g1.");
return 0;
}
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);
bool out;
C_KZG_RET ret = verify_kzg_proof(&out, commitment_native, z_native, y_native, proof_native, settings);
jbyte *z_native = (*env)->GetByteArrayElements(env, z, NULL);
jbyte *y_native = (*env)->GetByteArrayElements(env, y, NULL);
ret = verify_kzg_proof(&out, &c, (uint8_t *)z_native, (uint8_t *)y_native, &p, settings);
(*env)->ReleaseByteArrayElements(env, z, z_native, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, y, y_native, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, commitment, (jbyte *)commitment_native, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, z, (jbyte *)z_native, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, y, (jbyte *)y_native, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, proof, (jbyte *)proof_native, JNI_ABORT);
if (ret != C_KZG_OK)
{

View File

@ -149,9 +149,7 @@ Napi::Value BlobToKzgCommitment(const Napi::CallbackInfo& info) {
return env.Undefined();
};
uint8_t commitment_bytes[BYTES_PER_COMMITMENT];
bytes_from_g1(commitment_bytes, &commitment);
return napi_typed_array_from_bytes(commitment_bytes, BYTES_PER_COMMITMENT, env);
return napi_typed_array_from_bytes((uint8_t *)(&commitment), BYTES_PER_COMMITMENT, env);
}
// computeAggregateKzgProof: (blobs: Blob[], setupHandle: SetupHandle) => KZGProof;
@ -196,9 +194,7 @@ Napi::Value ComputeAggregateKzgProof(const Napi::CallbackInfo& info) {
return env.Undefined();
};
uint8_t proof_bytes[BYTES_PER_PROOF];
bytes_from_g1(proof_bytes, &proof);
return napi_typed_array_from_bytes(proof_bytes, BYTES_PER_PROOF, env);
return napi_typed_array_from_bytes((uint8_t *)(&proof), BYTES_PER_PROOF, env);
}
// verifyAggregateKzgProof: (blobs: Blob[], expectedKzgCommitments: KZGCommitment[], kzgAggregatedProof: KZGProof, setupHandle: SetupHandle) => boolean;
@ -238,39 +234,12 @@ Napi::Value VerifyAggregateKzgProof(const Napi::CallbackInfo& info) {
// Extract blob bytes from parameter
Napi::Value blob = blobs_param[blob_index];
auto blob_bytes = blob.As<Napi::Uint8Array>().Data();
memcpy(blobs[blob_index].bytes, blob_bytes, BYTES_PER_BLOB);
// Extract a G1 point for each commitment
// Extract commitment from parameter
Napi::Value commitment = commitments_param[blob_index];
auto commitment_bytes = commitment.As<Napi::Uint8Array>().Data();
ret = bytes_to_g1(&commitments[blob_index], commitment_bytes);
if (ret != C_KZG_OK) {
std::ostringstream ss;
std::copy(commitment_bytes, commitment_bytes + BYTES_PER_COMMITMENT, std::ostream_iterator<int>(ss, ","));
Napi::TypeError::New(
env,
"Invalid commitment data"
).ThrowAsJavaScriptException();
free(commitments);
free(blobs);
return env.Null();
}
}
KZGProof proof;
ret = bytes_to_g1(&proof, proof_bytes);
if (ret != C_KZG_OK) {
free(commitments);
free(blobs);
Napi::Error::New(env, "Invalid proof data")
.ThrowAsJavaScriptException();
return env.Null();
memcpy(&commitments[blob_index], commitment_bytes, BYTES_PER_COMMITMENT);
}
bool verification_result;
@ -279,7 +248,7 @@ Napi::Value VerifyAggregateKzgProof(const Napi::CallbackInfo& info) {
blobs,
commitments,
blobs_count,
&proof,
(KZGProof *)proof_bytes,
kzg_settings
);
@ -317,24 +286,17 @@ Napi::Value VerifyKzgProof(const Napi::CallbackInfo& info) {
return env.Null();
}
KZGCommitment commitment;
auto ret = bytes_to_g1(&commitment, polynomial_kzg);
if (ret != C_KZG_OK) {
std::ostringstream ss;
std::copy(polynomial_kzg, polynomial_kzg + BYTES_PER_COMMITMENT, std::ostream_iterator<int>(ss, ","));
Napi::TypeError::New(env, "Failed to parse argument commitment: " + ss.str() + " Return code was: " + std::to_string(ret)).ThrowAsJavaScriptException();
return env.Null();
};
KZGProof proof;
if (bytes_to_g1(&proof, kzg_proof) != C_KZG_OK) {
Napi::TypeError::New(env, "Invalid kzgProof").ThrowAsJavaScriptException();
return env.Null();
}
bool out;
if (verify_kzg_proof(&out, &commitment, z, y, &proof, kzg_settings) != C_KZG_OK) {
C_KZG_RET ret = verify_kzg_proof(
&out,
(KZGCommitment *)polynomial_kzg,
(BLSFieldElement *)z,
(BLSFieldElement *)y,
(KZGProof *)kzg_proof,
kzg_settings
);
if (ret != C_KZG_OK) {
Napi::TypeError::New(env, "Failed to verify KZG proof").ThrowAsJavaScriptException();
return env.Null();
}

View File

@ -105,7 +105,7 @@ describe("C-KZG", () => {
const proof = computeAggregateKzgProof(blobs);
expect(() =>
verifyAggregateKzgProof(blobs, commitments, proof),
).toThrowError("Invalid commitment data");
).toThrowError("verify_aggregate_kzg_proof failed with error code: 1");
});
describe("computing commitment from blobs", () => {

View File

@ -1,5 +1,5 @@
INCLUDE_DIRS = .. ../../src ../../inc
INCLUDE_PY = $(shell python -c 'import sysconfig; print(sysconfig.get_config_var("INCLUDEPY"))')
INCLUDE_PY = $(shell python3 -c 'import sysconfig; print(sysconfig.get_config_var("INCLUDEPY"))')
FIELD_ELEMENTS_PER_BLOB?=4096
@ -8,10 +8,10 @@ FIELD_ELEMENTS_PER_BLOB?=4096
all: test ecc_test
test: tests.py ckzg.so
python $<
python3 $<
ecc_test: py_ecc_tests.py ckzg.so
python $<
python3 $<
ckzg.so: ckzg.c ../../src/c_kzg_4844.o ../../lib/libblst.a
clang -O -Wall -shared -fPIC -Wl,-Bsymbolic -I${INCLUDE_PY} ${addprefix -I,${INCLUDE_DIRS}} -DFIELD_ELEMENTS_PER_BLOB=${FIELD_ELEMENTS_PER_BLOB} -o $@ $^

View File

@ -2,10 +2,6 @@
#include <Python.h>
#include "c_kzg_4844.h"
static void free_G1(PyObject *c) {
free(PyCapsule_GetPointer(c, "G1"));
}
static void free_KZGSettings(PyObject *c) {
KZGSettings *s = PyCapsule_GetPointer(c, "KZGSettings");
free_trusted_setup(s);
@ -39,21 +35,20 @@ static PyObject* blob_to_kzg_commitment_wrap(PyObject *self, PyObject *args) {
!PyCapsule_IsValid(s, "KZGSettings"))
return PyErr_Format(PyExc_ValueError, "expected bytes and trusted setup");
if (PyBytes_Size(b) != 32 * FIELD_ELEMENTS_PER_BLOB)
return PyErr_Format(PyExc_ValueError, "expected 32 * FIELD_ELEMENTS_PER_BLOB bytes");
if (PyBytes_Size(b) != BYTES_PER_BLOB)
return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_BLOB bytes");
Blob *blob = (Blob*)PyBytes_AsString(b);
KZGCommitment *k = (KZGCommitment*)malloc(sizeof(KZGCommitment));
if (k == NULL) return PyErr_NoMemory();
PyObject *out = PyBytes_FromStringAndSize(NULL, BYTES_PER_COMMITMENT);
if (out == NULL) return PyErr_NoMemory();
Blob *blob = (Blob *)PyBytes_AsString(b);
KZGCommitment *k = (KZGCommitment *)PyBytes_AsString(out);
if (blob_to_kzg_commitment(k, blob, PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
free(k);
Py_DECREF(out);
return PyErr_Format(PyExc_RuntimeError, "blob_to_kzg_commitment failed");
}
return PyCapsule_New(k, "G1", free_G1);
return out;
}
static PyObject* compute_aggregate_kzg_proof_wrap(PyObject *self, PyObject *args) {
@ -65,97 +60,70 @@ static PyObject* compute_aggregate_kzg_proof_wrap(PyObject *self, PyObject *args
return PyErr_Format(PyExc_ValueError, "expected bytes, trusted setup");
Py_ssize_t n = PyBytes_Size(b);
if (n % (32 * FIELD_ELEMENTS_PER_BLOB) != 0)
return PyErr_Format(PyExc_ValueError, "expected a multiple of 32 * FIELD_ELEMENTS_PER_BLOB bytes");
n = n / 32 / FIELD_ELEMENTS_PER_BLOB;
if (n % BYTES_PER_BLOB != 0)
return PyErr_Format(PyExc_ValueError, "expected blobs to be a multiple of BYTES_PER_BLOB bytes");
n = n / BYTES_PER_BLOB;
Blob* blobs = (Blob*)PyBytes_AsString(b);
KZGProof *k = (KZGProof*)malloc(sizeof(KZGProof));
if (k == NULL) {
return PyErr_NoMemory();
}
PyObject *out = PyBytes_FromStringAndSize(NULL, BYTES_PER_PROOF);
if (out == NULL) return PyErr_NoMemory();
Blob *blobs = (Blob *)PyBytes_AsString(b);
KZGProof *k = (KZGProof *)PyBytes_AsString(out);
if (compute_aggregate_kzg_proof(k, blobs, n,
PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
free(k);
Py_DECREF(out);
return PyErr_Format(PyExc_RuntimeError, "compute_aggregate_kzg_proof failed");
}
return PyCapsule_New(k, "G1", free_G1);
return out;
}
static PyObject* verify_aggregate_kzg_proof_wrap(PyObject *self, PyObject *args) {
PyObject *b, *c, *p, *s, *e;
PyObject *b, *c, *p, *s;
if (!PyArg_UnpackTuple(args, "verify_aggregate_kzg_proof", 4, 4, &b, &c, &p, &s) ||
!PyBytes_Check(b) ||
!PySequence_Check(c) ||
!PyCapsule_IsValid(p, "G1") ||
!PyBytes_Check(c) ||
!PyBytes_Check(p) ||
!PyCapsule_IsValid(s, "KZGSettings"))
return PyErr_Format(PyExc_ValueError,
"expected bytes, sequence, proof, trusted setup");
"expected bytes, bytes, bytes, trusted setup");
if (PyBytes_Size(p) != BYTES_PER_PROOF)
return PyErr_Format(PyExc_ValueError, "expected proof to be BYTES_PER_PROOF bytes");
Py_ssize_t n = PyBytes_Size(b);
if (n % (32 * FIELD_ELEMENTS_PER_BLOB) != 0)
return PyErr_Format(PyExc_ValueError, "expected a multiple of 32 * FIELD_ELEMENTS_PER_BLOB bytes");
n = n / 32 / FIELD_ELEMENTS_PER_BLOB;
if (n % BYTES_PER_BLOB != 0)
return PyErr_Format(PyExc_ValueError, "expected blobs to be a multiple of BYTES_PER_BLOB bytes");
n = n / BYTES_PER_BLOB;
if (PySequence_Length(c) != n)
Py_ssize_t m = PyBytes_Size(c);
if (m % BYTES_PER_COMMITMENT != 0)
return PyErr_Format(PyExc_ValueError, "expected commitments to be a multiple of BYTES_PER_COMMITMENT bytes");
m = m / BYTES_PER_COMMITMENT;
if (m != n)
return PyErr_Format(PyExc_ValueError, "expected same number of commitments as polynomials");
KZGCommitment* commitments = calloc(n, sizeof(KZGCommitment));
if (commitments == NULL) {
return PyErr_NoMemory();
}
Blob* blobs = (Blob*)PyBytes_AsString(b);
for (Py_ssize_t i = 0; i < n; i++) {
e = PySequence_GetItem(c, i);
if (!PyCapsule_IsValid(e, "G1")) {
free(commitments);
return PyErr_Format(PyExc_ValueError, "expected G1 capsules");
}
memcpy(&commitments[i], PyCapsule_GetPointer(e, "G1"), sizeof(KZGCommitment));
}
const Blob* blobs = (Blob *)PyBytes_AsString(b);
const KZGProof *proof = (KZGProof *)PyBytes_AsString(p);
const KZGCommitment *commitments = (KZGCommitment *)PyBytes_AsString(c);
bool out;
if (verify_aggregate_kzg_proof(&out,
blobs, commitments, n,
PyCapsule_GetPointer(p, "G1"),
blobs, commitments, n, proof,
PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
free(commitments);
return PyErr_Format(PyExc_RuntimeError, "verify_aggregate_kzg_proof failed");
}
free(commitments);
if (out) Py_RETURN_TRUE; else Py_RETURN_FALSE;
}
static PyObject* bytes_from_g1_wrap(PyObject *self, PyObject *args) {
PyObject *c;
if (!PyArg_UnpackTuple(args, "bytes_from_g1", 1, 1, &c) ||
!PyCapsule_IsValid(c, "G1"))
return PyErr_Format(PyExc_ValueError, "expected G1 capsule");
uint8_t bytes[48];
bytes_from_g1(bytes, PyCapsule_GetPointer(c, "G1"));
return PyBytes_FromStringAndSize((char*)bytes, 48);
}
static PyMethodDef ckzgmethods[] = {
{"load_trusted_setup", load_trusted_setup_wrap, METH_VARARGS, "Load trusted setup from file path"},
{"blob_to_kzg_commitment", blob_to_kzg_commitment_wrap, METH_VARARGS, "Create a commitment from a blob"},
{"compute_aggregate_kzg_proof", compute_aggregate_kzg_proof_wrap, METH_VARARGS, "Compute aggregate KZG proof"},
{"verify_aggregate_kzg_proof", verify_aggregate_kzg_proof_wrap, METH_VARARGS, "Verify aggregate KZG proof"},
// for tests/debugging
{"bytes_from_g1", bytes_from_g1_wrap, METH_VARARGS, "Convert a group element to 48 bytes"},
{NULL, NULL, 0, NULL}
};

View File

@ -61,7 +61,7 @@ ts_pyecc = load_trusted_setup("../../src/trusted_setup.txt")
commitment_pyecc = kzg_proofs.commit_to_poly(polynomial, ts_pyecc)
commitment_ckzg = ckzg.blob_to_kzg_commitment(b''.join([r.to_bytes(32, "little") for r in polynomial_l_rbo]), ts)
assert compress_G1(commitment_pyecc).to_bytes(48, "big") == ckzg.bytes_from_g1(commitment_ckzg)
assert compress_G1(commitment_pyecc).to_bytes(48, "big") == commitment_ckzg
# TODO: update this test for the new ckzg interface
# proof_pyecc = kzg_proofs.compute_proof_single(polynomial, x, ts_pyecc)

View File

@ -14,7 +14,7 @@ blobs = [
ts = ckzg.load_trusted_setup("../../src/trusted_setup.txt")
kzg_commitments = [ckzg.blob_to_kzg_commitment(blob, ts) for blob in blobs]
kzg_commitments = b''.join([ckzg.blob_to_kzg_commitment(blob, ts) for blob in blobs])
# Compute proof for these blobs

View File

@ -6,25 +6,25 @@ use rand::{rngs::ThreadRng, Rng};
use std::sync::Arc;
fn generate_random_blob_for_bench(rng: &mut ThreadRng) -> Blob {
let mut arr: Blob = [0; BYTES_PER_BLOB];
let mut arr = [0u8; BYTES_PER_BLOB];
rng.fill(&mut arr[..]);
// Ensure that the blob is canonical by ensuring that
// each field element contained in the blob is < BLS_MODULUS
for i in 0..FIELD_ELEMENTS_PER_BLOB {
arr[i * BYTES_PER_FIELD_ELEMENT + BYTES_PER_FIELD_ELEMENT - 1] = 0;
}
arr
arr.into()
}
pub fn criterion_benchmark(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
assert!(trusted_setup_file.exists());
let kzg_settings = Arc::new(KzgSettings::load_trusted_setup_file(trusted_setup_file).unwrap());
let kzg_settings = Arc::new(KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap());
let blob = generate_random_blob_for_bench(&mut rng);
c.bench_function("blob_to_kzg_commitment", |b| {
b.iter(|| KzgCommitment::blob_to_kzg_commitment(blob, &kzg_settings))
b.iter(|| KZGCommitment::blob_to_kzg_commitment(blob, &kzg_settings))
});
for num_blobs in [4, 8, 16].iter() {
@ -37,15 +37,15 @@ pub fn criterion_benchmark(c: &mut Criterion) {
group.bench_with_input(
BenchmarkId::new("compute_aggregate_kzg_proof", *num_blobs),
&blobs,
|b, blobs| b.iter(|| KzgProof::compute_aggregate_kzg_proof(blobs, &kzg_settings)),
|b, blobs| b.iter(|| KZGProof::compute_aggregate_kzg_proof(blobs, &kzg_settings)),
);
let kzg_commitments: Vec<KzgCommitment> = blobs
let kzg_commitments: Vec<KZGCommitment> = blobs
.clone()
.into_iter()
.map(|blob| KzgCommitment::blob_to_kzg_commitment(blob, &kzg_settings))
.map(|blob| KZGCommitment::blob_to_kzg_commitment(blob, &kzg_settings))
.collect();
let proof = KzgProof::compute_aggregate_kzg_proof(&blobs, &kzg_settings).unwrap();
let proof = KZGProof::compute_aggregate_kzg_proof(&blobs, &kzg_settings).unwrap();
group.bench_with_input(
BenchmarkId::new("verify_aggregate_kzg_proof", *num_blobs),

View File

@ -2,6 +2,8 @@
include!("./consts.rs");
use std::ops::{Deref, DerefMut};
use libc::FILE;
pub const BYTES_PER_COMMITMENT: usize = 48;
@ -9,97 +11,145 @@ pub const BYTES_PER_PROOF: usize = 48;
pub const BYTES_PER_FIELD_ELEMENT: usize = 32;
pub const BYTES_PER_BLOB: usize = FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT;
pub type byte = u8;
pub type limb_t = u64;
type byte = u8;
type limb_t = u64;
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_scalar {
pub b: [byte; 32usize],
struct blst_scalar {
b: [byte; 32usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_fr {
pub l: [limb_t; 4usize],
struct blst_fr {
l: [limb_t; 4usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_fp {
pub l: [limb_t; 6usize],
struct blst_fp {
l: [limb_t; 6usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_fp2 {
pub fp: [blst_fp; 2usize],
struct blst_fp2 {
fp: [blst_fp; 2usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_fp6 {
pub fp2: [blst_fp2; 3usize],
struct blst_fp6 {
fp2: [blst_fp2; 3usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_fp12 {
pub fp6: [blst_fp6; 2usize],
struct blst_fp12 {
fp6: [blst_fp6; 2usize],
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_p1 {
pub x: blst_fp,
pub y: blst_fp,
pub z: blst_fp,
struct blst_p1 {
x: blst_fp,
y: blst_fp,
z: blst_fp,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_p1_affine {
pub x: blst_fp,
pub y: blst_fp,
struct blst_p1_affine {
x: blst_fp,
y: blst_fp,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_p2 {
pub x: blst_fp2,
pub y: blst_fp2,
pub z: blst_fp2,
struct blst_p2 {
x: blst_fp2,
y: blst_fp2,
z: blst_fp2,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct blst_p2_affine {
pub x: blst_fp2,
pub y: blst_fp2,
struct blst_p2_affine {
x: blst_fp2,
y: blst_fp2,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct BLSFieldElement {
bytes: [u8; BYTES_PER_FIELD_ELEMENT],
}
impl Deref for BLSFieldElement {
type Target = [u8; BYTES_PER_FIELD_ELEMENT];
fn deref(&self) -> &Self::Target {
&self.bytes
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Blob {
bytes: [u8; BYTES_PER_BLOB],
}
impl Deref for Blob {
type Target = [u8; BYTES_PER_BLOB];
fn deref(&self) -> &Self::Target {
&self.bytes
}
}
impl DerefMut for Blob {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.bytes
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct KZGProof {
bytes: [u8; BYTES_PER_PROOF],
}
impl Deref for KZGProof {
type Target = [u8; BYTES_PER_PROOF];
fn deref(&self) -> &Self::Target {
&self.bytes
}
}
pub const FIAT_SHAMIR_PROTOCOL_DOMAIN: &[u8; 16usize] = b"FSBLOBVERIFY_V1_";
type g1_t = blst_p1;
type g2_t = blst_p2;
type fr_t = blst_fr;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct KZGCommitment {
bytes: [u8; BYTES_PER_COMMITMENT],
}
impl Deref for KZGCommitment {
type Target = [u8; BYTES_PER_COMMITMENT];
fn deref(&self) -> &Self::Target {
&self.bytes
}
}
pub const FIAT_SHAMIR_PROTOCOL_DOMAIN: [u8; 16usize] = [
70, 83, 66, 76, 79, 66, 86, 69, 82, 73, 70, 89, 95, 86, 49, 95,
];
pub type g1_t = blst_p1;
pub type g2_t = blst_p2;
pub type fr_t = blst_fr;
pub type KZGCommitment = g1_t;
pub type KZGProof = g1_t;
pub type BLSFieldElement = fr_t;
pub type Blob = [u8; BYTES_PER_BLOB];
#[repr(u32)]
#[doc = " The common return type for all routines in which something can go wrong."]
#[doc = ""]
#[doc = " @warning In the case of @p C_KZG_OK or @p C_KZG_BADARGS, the caller can assume that all memory allocated by the"]
#[doc = " called routines has been deallocated. However, in the case of @p C_KZG_ERROR or @p C_KZG_MALLOC being returned, these"]
#[doc = " are unrecoverable and memory may have been leaked."]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum C_KZG_RET {
#[doc = "< Success!"]
C_KZG_OK = 0,
#[doc = "< The supplied data is invalid in some way"]
#[doc = "< The supplied data is invalid in some way."]
C_KZG_BADARGS = 1,
#[doc = "< Internal error - this should never occur and may indicate a bug in the library"]
#[doc = "< Internal error - this should never occur and may indicate a bug in the library."]
C_KZG_ERROR = 2,
#[doc = "< Could not allocate memory"]
#[doc = "< Could not allocate memory."]
C_KZG_MALLOC = 3,
}
#[doc = " Stores the setup and parameters needed for performing FFTs."]
@ -107,80 +157,25 @@ pub enum C_KZG_RET {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct FFTSettings {
#[doc = "< The maximum size of FFT these settings support, a power of 2."]
pub max_width: u64,
max_width: u64,
#[doc = "< Ascending powers of the root of unity, size `width + 1`."]
pub expanded_roots_of_unity: *const fr_t,
expanded_roots_of_unity: *const fr_t,
#[doc = "< Descending powers of the root of unity, size `width + 1`."]
pub reverse_roots_of_unity: *const fr_t,
reverse_roots_of_unity: *const fr_t,
#[doc = "< Powers of the root of unity in bit-reversal permutation, size `width`."]
pub roots_of_unity: *const fr_t,
roots_of_unity: *const fr_t,
}
#[test]
fn bindgen_test_layout_FFTSettings() {
const UNINIT: ::std::mem::MaybeUninit<FFTSettings> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<FFTSettings>(),
32usize,
concat!("Size of: ", stringify!(FFTSettings))
);
assert_eq!(
::std::mem::align_of::<FFTSettings>(),
8usize,
concat!("Alignment of ", stringify!(FFTSettings))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).max_width) as usize - ptr as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(FFTSettings),
"::",
stringify!(max_width)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).expanded_roots_of_unity) as usize - ptr as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(FFTSettings),
"::",
stringify!(expanded_roots_of_unity)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).reverse_roots_of_unity) as usize - ptr as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(FFTSettings),
"::",
stringify!(reverse_roots_of_unity)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).roots_of_unity) as usize - ptr as usize },
24usize,
concat!(
"Offset of field: ",
stringify!(FFTSettings),
"::",
stringify!(roots_of_unity)
)
);
}
#[doc = " Stores the setup and parameters needed for computing KZG proofs."]
#[repr(C)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KZGSettings {
#[doc = "< The corresponding settings for performing FFTs"]
pub fs: *const FFTSettings,
#[doc = "< G1 group elements from the trusted setup, in Lagrange form bit-reversal permutation"]
pub g1_values: *const g1_t,
#[doc = "< G2 group elements from the trusted setup; both arrays have FIELD_ELEMENTS_PER_BLOB elements"]
pub g2_values: *const g2_t,
#[doc = "< The corresponding settings for performing FFTs."]
fs: *const FFTSettings,
#[doc = "< G1 group elements from the trusted setup, in Lagrange form bit-reversal permutation."]
g1_values: *const g1_t,
#[doc = "< G2 group elements from the trusted setup; both arrays have FIELD_ELEMENTS_PER_BLOB elements."]
g2_values: *const g2_t,
}
/// Safety: FFTSettings is initialized once on calling `load_trusted_setup`. After
@ -190,65 +185,8 @@ pub struct KZGSettings {
unsafe impl Sync for KZGSettings {}
unsafe impl Send for KZGSettings {}
#[test]
fn bindgen_test_layout_KZGSettings() {
const UNINIT: ::std::mem::MaybeUninit<KZGSettings> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<KZGSettings>(),
24usize,
concat!("Size of: ", stringify!(KZGSettings))
);
assert_eq!(
::std::mem::align_of::<KZGSettings>(),
8usize,
concat!("Alignment of ", stringify!(KZGSettings))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).fs) as usize - ptr as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(KZGSettings),
"::",
stringify!(fs)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).g1_values) as usize - ptr as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(KZGSettings),
"::",
stringify!(g1_values)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).g2_values) as usize - ptr as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(KZGSettings),
"::",
stringify!(g2_values)
)
);
}
extern "C" {
#[doc = " Interface functions"]
pub fn bytes_to_g1(out: *mut g1_t, in_: *const u8) -> C_KZG_RET;
}
extern "C" {
pub fn bytes_from_g1(out: *mut u8, in_: *const g1_t);
}
extern "C" {
pub fn bytes_to_bls_field(out: *mut BLSFieldElement, in_: *const u8) -> C_KZG_RET;
}
extern "C" {
pub fn load_trusted_setup_file(out: *mut KZGSettings, in_: *mut FILE) -> C_KZG_RET;
}
extern "C" {
pub fn load_trusted_setup(
out: *mut KZGSettings,
g1_bytes: *const u8, /* n1 * 48 bytes */
@ -257,13 +195,16 @@ extern "C" {
n2: usize,
) -> C_KZG_RET;
}
extern "C" {
pub fn load_trusted_setup_file(out: *mut KZGSettings, in_: *mut FILE) -> C_KZG_RET;
}
extern "C" {
pub fn free_trusted_setup(s: *mut KZGSettings);
}
extern "C" {
pub fn compute_aggregate_kzg_proof(
out: *mut KZGProof,
blobs: *const u8, // pointer to the first byte in a 2D array ([[u8; BYTES_PER_BLOB]])
blobs: *const Blob,
n: usize,
s: *const KZGSettings,
) -> C_KZG_RET;
@ -271,7 +212,7 @@ extern "C" {
extern "C" {
pub fn verify_aggregate_kzg_proof(
out: *mut bool,
blobs: *const u8, // pointer to the first byte in a 2D array ([[u8; BYTES_PER_BLOB]])
blobs: *const Blob,
expected_kzg_commitments: *const KZGCommitment,
n: usize,
kzg_aggregated_proof: *const KZGProof,
@ -279,14 +220,18 @@ extern "C" {
) -> C_KZG_RET;
}
extern "C" {
pub fn blob_to_kzg_commitment(out: *mut KZGCommitment, blob: *mut u8, s: *const KZGSettings);
pub fn blob_to_kzg_commitment(
out: *mut KZGCommitment,
blob: *const Blob,
s: *const KZGSettings,
) -> C_KZG_RET;
}
extern "C" {
pub fn verify_kzg_proof(
out: *mut bool,
polynomial_kzg: *const KZGCommitment,
z: *const u8,
y: *const u8,
z: *const BLSFieldElement,
y: *const BLSFieldElement,
kzg_proof: *const KZGProof,
s: *const KZGSettings,
) -> C_KZG_RET;

View File

@ -2,19 +2,14 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
mod bindings;
use bindings::{g1_t, C_KZG_RET};
include!("bindings.rs");
use libc::fopen;
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::os::unix::prelude::OsStrExt;
use std::path::PathBuf;
pub use bindings::{
Blob, BYTES_PER_BLOB, BYTES_PER_COMMITMENT, BYTES_PER_FIELD_ELEMENT, BYTES_PER_PROOF,
FIAT_SHAMIR_PROTOCOL_DOMAIN, FIELD_ELEMENTS_PER_BLOB,
};
pub const BYTES_PER_G1_POINT: usize = 48;
pub const BYTES_PER_G2_POINT: usize = 96;
@ -34,44 +29,8 @@ pub enum Error {
CError(C_KZG_RET),
}
pub fn bytes_to_g1(bytes: &[u8]) -> Result<g1_t, Error> {
let mut g1_point = MaybeUninit::<g1_t>::uninit();
unsafe {
let res = bindings::bytes_to_g1(g1_point.as_mut_ptr(), bytes.as_ptr());
if let C_KZG_RET::C_KZG_OK = res {
Ok(g1_point.assume_init())
} else {
Err(Error::CError(res))
}
}
}
pub fn bytes_from_g1(g1_point: g1_t) -> [u8; BYTES_PER_G1_POINT] {
let mut bytes = [0; 48];
unsafe { bindings::bytes_from_g1(bytes.as_mut_ptr(), &g1_point) }
bytes
}
#[derive(Debug, Clone, Copy)]
pub struct BlsFieldElement(bindings::BLSFieldElement);
impl BlsFieldElement {
pub fn bytes_to_bls_field(bytes: [u8; BYTES_PER_FIELD_ELEMENT]) -> Result<Self, Error> {
let mut bls_field_element = MaybeUninit::<bindings::BLSFieldElement>::uninit();
unsafe {
let res = bindings::bytes_to_bls_field(bls_field_element.as_mut_ptr(), bytes.as_ptr());
if let C_KZG_RET::C_KZG_OK = res {
Ok(Self(bls_field_element.assume_init()))
} else {
Err(Error::CError(res))
}
}
}
}
/// Holds the parameters of a kzg trusted setup ceremony.
pub struct KzgSettings(bindings::KZGSettings);
impl KzgSettings {
impl KZGSettings {
/// Initializes a trusted setup from `FIELD_ELEMENTS_PER_BLOB` g1 points
/// and 65 g2 points in byte format.
pub fn load_trusted_setup(
@ -92,12 +51,12 @@ impl KzgSettings {
g2_bytes.len()
)));
}
let mut kzg_settings = MaybeUninit::<bindings::KZGSettings>::uninit();
let mut kzg_settings = MaybeUninit::<KZGSettings>::uninit();
unsafe {
let n1 = g1_bytes.len();
let n2 = g2_bytes.len();
let res = bindings::load_trusted_setup(
let res = load_trusted_setup(
kzg_settings.as_mut_ptr(),
g1_bytes.as_ptr() as *const u8,
n1,
@ -105,7 +64,7 @@ impl KzgSettings {
n2,
);
if let C_KZG_RET::C_KZG_OK = res {
Ok(Self(kzg_settings.assume_init()))
Ok(kzg_settings.assume_init())
} else {
Err(Error::InvalidTrustedSetup(format!(
"Invalid trusted setup: {:?}",
@ -125,12 +84,12 @@ impl KzgSettings {
let file_path = CString::new(file_path.as_os_str().as_bytes()).map_err(|e| {
Error::InvalidTrustedSetup(format!("Invalid trusted setup file: {:?}", e))
})?;
let mut kzg_settings = MaybeUninit::<bindings::KZGSettings>::uninit();
let mut kzg_settings = MaybeUninit::<KZGSettings>::uninit();
unsafe {
let file_ptr = fopen(file_path.as_ptr(), &('r' as libc::c_char));
let res = bindings::load_trusted_setup_file(kzg_settings.as_mut_ptr(), file_ptr);
let res = load_trusted_setup_file(kzg_settings.as_mut_ptr(), file_ptr);
if let C_KZG_RET::C_KZG_OK = res {
Ok(Self(kzg_settings.assume_init()))
Ok(kzg_settings.assume_init())
} else {
Err(Error::InvalidTrustedSetup(format!(
"Invalid trusted setup: {:?}",
@ -141,15 +100,13 @@ impl KzgSettings {
}
}
impl Drop for KzgSettings {
impl Drop for KZGSettings {
fn drop(&mut self) {
unsafe { bindings::free_trusted_setup(&mut self.0) }
unsafe { free_trusted_setup(self) }
}
}
pub struct KzgProof(bindings::KZGProof);
impl KzgProof {
impl KZGProof {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() != BYTES_PER_PROOF {
return Err(Error::InvalidKzgProof(format!(
@ -160,11 +117,11 @@ impl KzgProof {
}
let mut proof_bytes = [0; BYTES_PER_PROOF];
proof_bytes.copy_from_slice(bytes);
Ok(Self(bytes_to_g1(bytes)?))
Ok(Self { bytes: proof_bytes })
}
pub fn to_bytes(&self) -> [u8; BYTES_PER_G1_POINT] {
bytes_from_g1(self.0)
self.bytes
}
pub fn as_hex_string(&self) -> String {
@ -173,18 +130,18 @@ impl KzgProof {
pub fn compute_aggregate_kzg_proof(
blobs: &[Blob],
kzg_settings: &KzgSettings,
kzg_settings: &KZGSettings,
) -> Result<Self, Error> {
let mut kzg_proof = MaybeUninit::<bindings::KZGProof>::uninit();
let mut kzg_proof = MaybeUninit::<KZGProof>::uninit();
unsafe {
let res = bindings::compute_aggregate_kzg_proof(
let res = compute_aggregate_kzg_proof(
kzg_proof.as_mut_ptr(),
blobs.as_ptr() as *const u8,
blobs.as_ptr(),
blobs.len(),
&kzg_settings.0,
kzg_settings,
);
if let C_KZG_RET::C_KZG_OK = res {
Ok(Self(kzg_proof.assume_init()))
Ok(kzg_proof.assume_init())
} else {
Err(Error::CError(res))
}
@ -194,23 +151,18 @@ impl KzgProof {
pub fn verify_aggregate_kzg_proof(
&self,
blobs: &[Blob],
expected_kzg_commitments: &[KzgCommitment],
kzg_settings: &KzgSettings,
expected_kzg_commitments: &[KZGCommitment],
kzg_settings: &KZGSettings,
) -> Result<bool, Error> {
let mut verified: MaybeUninit<bool> = MaybeUninit::uninit();
unsafe {
// TODO: pass without allocating a vec
let res = bindings::verify_aggregate_kzg_proof(
let res = verify_aggregate_kzg_proof(
verified.as_mut_ptr(),
blobs.as_ptr() as *const u8,
expected_kzg_commitments
.iter()
.map(|c| c.0)
.collect::<Vec<_>>()
.as_ptr(),
blobs.as_ptr(),
expected_kzg_commitments.as_ptr(),
blobs.len(),
&self.0,
&kzg_settings.0,
self,
kzg_settings,
);
if let C_KZG_RET::C_KZG_OK = res {
Ok(verified.assume_init())
@ -222,20 +174,20 @@ impl KzgProof {
pub fn verify_kzg_proof(
&self,
kzg_commitment: KzgCommitment,
z: [u8; BYTES_PER_FIELD_ELEMENT],
y: [u8; BYTES_PER_FIELD_ELEMENT],
kzg_settings: &KzgSettings,
kzg_commitment: KZGCommitment,
z: BLSFieldElement,
y: BLSFieldElement,
kzg_settings: &KZGSettings,
) -> Result<bool, Error> {
let mut verified: MaybeUninit<bool> = MaybeUninit::uninit();
unsafe {
let res = bindings::verify_kzg_proof(
let res = verify_kzg_proof(
verified.as_mut_ptr(),
&kzg_commitment.0,
z.as_ptr(),
y.as_ptr(),
&self.0,
&kzg_settings.0,
&kzg_commitment,
&z,
&y,
self,
kzg_settings,
);
if let C_KZG_RET::C_KZG_OK = res {
Ok(verified.assume_init())
@ -246,9 +198,7 @@ impl KzgProof {
}
}
pub struct KzgCommitment(bindings::KZGCommitment);
impl KzgCommitment {
impl KZGCommitment {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() != BYTES_PER_COMMITMENT {
return Err(Error::InvalidKzgCommitment(format!(
@ -257,65 +207,89 @@ impl KzgCommitment {
bytes.len(),
)));
}
let mut proof_bytes = [0; BYTES_PER_COMMITMENT];
proof_bytes.copy_from_slice(bytes);
Ok(Self(bytes_to_g1(bytes)?))
let mut commitment = [0; BYTES_PER_COMMITMENT];
commitment.copy_from_slice(bytes);
Ok(Self { bytes: commitment })
}
pub fn to_bytes(&self) -> [u8; BYTES_PER_G1_POINT] {
bytes_from_g1(self.0)
self.bytes
}
pub fn as_hex_string(&self) -> String {
hex::encode(self.to_bytes())
}
pub fn blob_to_kzg_commitment(mut blob: Blob, kzg_settings: &KzgSettings) -> Self {
let mut kzg_commitment: MaybeUninit<bindings::KZGCommitment> = MaybeUninit::uninit();
pub fn blob_to_kzg_commitment(blob: Blob, kzg_settings: &KZGSettings) -> Self {
let mut kzg_commitment: MaybeUninit<KZGCommitment> = MaybeUninit::uninit();
unsafe {
bindings::blob_to_kzg_commitment(
blob_to_kzg_commitment(
kzg_commitment.as_mut_ptr(),
blob.as_mut_ptr(),
&kzg_settings.0,
blob.as_ptr() as *const Blob,
kzg_settings,
);
Self(kzg_commitment.assume_init())
kzg_commitment.assume_init()
}
}
}
impl From<[u8; BYTES_PER_COMMITMENT]> for KZGCommitment {
fn from(value: [u8; BYTES_PER_COMMITMENT]) -> Self {
Self { bytes: value }
}
}
impl From<[u8; BYTES_PER_PROOF]> for KZGProof {
fn from(value: [u8; BYTES_PER_PROOF]) -> Self {
Self { bytes: value }
}
}
impl From<[u8; BYTES_PER_BLOB]> for Blob {
fn from(value: [u8; BYTES_PER_BLOB]) -> Self {
Self { bytes: value }
}
}
impl From<[u8; BYTES_PER_FIELD_ELEMENT]> for BLSFieldElement {
fn from(value: [u8; BYTES_PER_FIELD_ELEMENT]) -> Self {
Self { bytes: value }
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::{rngs::ThreadRng, Rng};
fn generate_random_blob(rng: &mut ThreadRng) -> Blob {
let mut arr: Blob = [0; BYTES_PER_BLOB];
let mut arr = [0u8; BYTES_PER_BLOB];
rng.fill(&mut arr[..]);
// Ensure that the blob is canonical by ensuring that
// each field element contained in the blob is < BLS_MODULUS
for i in 0..FIELD_ELEMENTS_PER_BLOB {
arr[i * BYTES_PER_FIELD_ELEMENT + BYTES_PER_FIELD_ELEMENT - 1] = 0;
}
arr
arr.into()
}
fn test_simple(trusted_setup_file: PathBuf) {
let mut rng = rand::thread_rng();
assert!(trusted_setup_file.exists());
let kzg_settings = KzgSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
let num_blobs: usize = rng.gen_range(0..16);
let mut blobs: Vec<Blob> = (0..num_blobs)
.map(|_| generate_random_blob(&mut rng))
.collect();
let kzg_commitments: Vec<KzgCommitment> = blobs
let kzg_commitments: Vec<KZGCommitment> = blobs
.clone()
.into_iter()
.map(|blob| KzgCommitment::blob_to_kzg_commitment(blob, &kzg_settings))
.map(|blob| KZGCommitment::blob_to_kzg_commitment(blob, &kzg_settings))
.collect();
let kzg_proof = KzgProof::compute_aggregate_kzg_proof(&blobs, &kzg_settings).unwrap();
let kzg_proof = KZGProof::compute_aggregate_kzg_proof(&blobs, &kzg_settings).unwrap();
assert!(kzg_proof
.verify_aggregate_kzg_proof(&blobs, &kzg_commitments, &kzg_settings)
@ -345,7 +319,7 @@ mod tests {
fn test_compute_agg_proof() {
let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
assert!(trusted_setup_file.exists());
let kzg_settings = KzgSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
let test_file = PathBuf::from("test_vectors/public_agg_proof.json");
let json_data: serde_json::Value =
@ -375,15 +349,15 @@ mod tests {
let blob = hex::decode(data).unwrap();
let mut blob_data = [0; BYTES_PER_BLOB];
blob_data.copy_from_slice(&blob);
blob_data
Blob { bytes: blob_data }
})
.collect::<Vec<_>>();
let proof = KzgProof::compute_aggregate_kzg_proof(&blobs, &kzg_settings).unwrap();
let proof = KZGProof::compute_aggregate_kzg_proof(&blobs, &kzg_settings).unwrap();
assert_eq!(proof.as_hex_string(), expected_proof);
for (i, blob) in blobs.into_iter().enumerate() {
let commitment = KzgCommitment::blob_to_kzg_commitment(blob, &kzg_settings);
let commitment = KZGCommitment::blob_to_kzg_commitment(blob, &kzg_settings);
assert_eq!(
commitment.as_hex_string().as_str(),
expected_kzg_commitments[i]
@ -397,7 +371,7 @@ mod tests {
fn test_verify_kzg_proof() {
let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
assert!(trusted_setup_file.exists());
let kzg_settings = KzgSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
let test_file = PathBuf::from("test_vectors/public_verify_kzg_proof.json");
let json_data: serde_json::Value =
@ -406,11 +380,11 @@ mod tests {
let tests = json_data.get("TestCases").unwrap().as_array().unwrap();
for test in tests.iter() {
let proof = test.get("Proof").unwrap().as_str().unwrap();
let kzg_proof = KzgProof::from_bytes(&hex::decode(proof).unwrap()).unwrap();
let kzg_proof = KZGProof::from_bytes(&hex::decode(proof).unwrap()).unwrap();
let commitment = test.get("Commitment").unwrap().as_str().unwrap();
let kzg_commitment =
KzgCommitment::from_bytes(&hex::decode(commitment).unwrap()).unwrap();
KZGCommitment::from_bytes(&hex::decode(commitment).unwrap()).unwrap();
let z = test.get("InputPoint").unwrap().as_str().unwrap();
let mut z_bytes = [0; BYTES_PER_FIELD_ELEMENT];
@ -421,7 +395,12 @@ mod tests {
y_bytes.copy_from_slice(&hex::decode(y).unwrap());
assert!(kzg_proof
.verify_kzg_proof(kzg_commitment, z_bytes, y_bytes, &kzg_settings)
.verify_kzg_proof(
kzg_commitment,
z_bytes.into(),
y_bytes.into(),
&kzg_settings
)
.unwrap());
}
}

View File

@ -790,13 +790,13 @@ static bool pairings_verify(const g1_t *a1, const g2_t *a2, const g1_t *b1, cons
return blst_fp12_is_one(&gt_point);
}
typedef struct { BLSFieldElement evals[FIELD_ELEMENTS_PER_BLOB]; } Polynomial;
typedef struct { fr_t evals[FIELD_ELEMENTS_PER_BLOB]; } Polynomial;
void bytes_from_g1(uint8_t out[48], const g1_t *in) {
static void bytes_from_g1(uint8_t out[48], const g1_t *in) {
blst_p1_compress(out, in);
}
C_KZG_RET bytes_to_g1(g1_t* out, const uint8_t bytes[48]) {
static C_KZG_RET bytes_to_g1(g1_t* out, const uint8_t bytes[48]) {
blst_p1_affine tmp;
if (blst_p1_uncompress(&tmp, bytes) != BLST_SUCCESS)
return C_KZG_BADARGS;
@ -804,11 +804,11 @@ C_KZG_RET bytes_to_g1(g1_t* out, const uint8_t bytes[48]) {
return C_KZG_OK;
}
static void bytes_from_bls_field(uint8_t out[32], const BLSFieldElement *in) {
static void bytes_from_bls_field(uint8_t out[32], const fr_t *in) {
blst_scalar_from_fr((blst_scalar*)out, in);
}
C_KZG_RET load_trusted_setup(KZGSettings *out, const uint8_t g1_bytes[], size_t n1, const uint8_t g2_bytes[], size_t n2) {
C_KZG_RET load_trusted_setup(KZGSettings *out, const uint8_t *g1_bytes, size_t n1, const uint8_t *g2_bytes, size_t n2) {
uint64_t i;
blst_p2_affine g2_affine;
g1_t *g1_projective = NULL;
@ -890,21 +890,21 @@ void free_trusted_setup(KZGSettings *s) {
free_kzg_settings(s);
}
static void compute_powers(BLSFieldElement out[], BLSFieldElement *x, uint64_t n) {
BLSFieldElement current_power = fr_one;
static void compute_powers(fr_t *out, fr_t *x, uint64_t n) {
fr_t current_power = fr_one;
for (uint64_t i = 0; i < n; i++) {
out[i] = current_power;
fr_mul(&current_power, &current_power, x);
}
}
static void hash_to_bls_field(BLSFieldElement *out, const uint8_t bytes[32]) {
static void hash_to_bls_field(fr_t *out, const uint8_t bytes[32]) {
blst_scalar tmp;
blst_scalar_from_lendian(&tmp, bytes);
blst_fr_from_scalar(out, &tmp);
}
C_KZG_RET bytes_to_bls_field(BLSFieldElement *out, const uint8_t bytes[32]) {
static C_KZG_RET bytes_to_bls_field(fr_t *out, const uint8_t bytes[32]) {
blst_scalar tmp;
blst_scalar_from_lendian(&tmp, bytes);
if (!blst_scalar_fr_check(&tmp)) return C_KZG_BADARGS;
@ -912,7 +912,7 @@ C_KZG_RET bytes_to_bls_field(BLSFieldElement *out, const uint8_t bytes[32]) {
return C_KZG_OK;
}
static void poly_lincomb(Polynomial *out, const Polynomial *vectors, const fr_t scalars[], uint64_t n) {
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++)
@ -992,7 +992,7 @@ static C_KZG_RET g1_lincomb(g1_t *out, const g1_t *p, const fr_t *coeffs, const
return C_KZG_OK;
}
static C_KZG_RET poly_to_kzg_commitment(KZGCommitment *out, const Polynomial *p, const KZGSettings *s) {
static C_KZG_RET poly_to_kzg_commitment(g1_t *out, const Polynomial *p, const KZGSettings *s) {
return g1_lincomb(out, s->g1_values, (const fr_t *)(&p->evals), FIELD_ELEMENTS_PER_BLOB);
}
@ -1006,10 +1006,16 @@ static C_KZG_RET poly_from_blob(Polynomial *p, const Blob *blob) {
}
C_KZG_RET blob_to_kzg_commitment(KZGCommitment *out, const Blob *blob, const KZGSettings *s) {
C_KZG_RET ret;
Polynomial p;
C_KZG_RET ret = poly_from_blob(&p, blob);
g1_t commitment;
ret = poly_from_blob(&p, blob);
if (ret != C_KZG_OK) return ret;
return poly_to_kzg_commitment(out, &p, s);
ret = poly_to_kzg_commitment(&commitment, &p, s);
if (ret != C_KZG_OK) return ret;
bytes_from_g1((uint8_t *)(out), &commitment);
return C_KZG_OK;
}
/**
@ -1041,20 +1047,27 @@ 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 uint8_t z[BYTES_PER_FIELD_ELEMENT],
const uint8_t y[BYTES_PER_FIELD_ELEMENT],
const BLSFieldElement *z,
const BLSFieldElement *y,
const KZGProof *kzg_proof,
const KZGSettings *s) {
BLSFieldElement frz, fry;
C_KZG_RET ret;
ret = bytes_to_bls_field(&frz, z);
fr_t frz, fry;
g1_t g1commitment, g1proof;
ret = bytes_to_g1(&g1commitment, (const uint8_t *)(commitment));
if (ret != C_KZG_OK) return ret;
ret = bytes_to_bls_field(&fry, y);
ret = bytes_to_bls_field(&frz, (const uint8_t *)(z));
if (ret != C_KZG_OK) return ret;
return verify_kzg_proof_impl(out, commitment, &frz, &fry, kzg_proof, s);
ret = bytes_to_bls_field(&fry, (const uint8_t *)(y));
if (ret != C_KZG_OK) return ret;
ret = bytes_to_g1(&g1proof, (const uint8_t *)(kzg_proof));
if (ret != C_KZG_OK) return ret;
return verify_kzg_proof_impl(out, &g1commitment, &frz, &fry, &g1proof, s);
}
static C_KZG_RET evaluate_polynomial_in_evaluation_form(BLSFieldElement *out, const Polynomial *p, const BLSFieldElement *x, const KZGSettings *s) {
static C_KZG_RET evaluate_polynomial_in_evaluation_form(fr_t *out, const Polynomial *p, const fr_t *x, const KZGSettings *s) {
C_KZG_RET ret;
fr_t tmp;
fr_t *inverses_in = NULL;
@ -1107,9 +1120,9 @@ out:
* @retval C_KZG_OK All is well
* @retval C_KZG_MALLOC Memory allocation failed
*/
static C_KZG_RET compute_kzg_proof(KZGProof *out, const Polynomial *p, const BLSFieldElement *x, const KZGSettings *s) {
static C_KZG_RET compute_kzg_proof(g1_t *out, const Polynomial *p, const fr_t *x, const KZGSettings *s) {
C_KZG_RET ret;
BLSFieldElement y;
fr_t y;
fr_t *inverses_in = NULL;
fr_t *inverses = NULL;
@ -1180,7 +1193,7 @@ void sha256_init(SHA256_CTX *ctx);
void sha256_update(SHA256_CTX *ctx, const void *_inp, size_t len);
void sha256_final(unsigned char md[32], SHA256_CTX *ctx);
static void hash(uint8_t md[32], const uint8_t input[], size_t n) {
static void hash(uint8_t md[32], const uint8_t *input, size_t n) {
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, input, n);
@ -1194,8 +1207,8 @@ static void bytes_of_uint64(uint8_t out[8], uint64_t n) {
}
}
static C_KZG_RET compute_challenges(BLSFieldElement *out, BLSFieldElement r_powers[],
const Polynomial *polys, const KZGCommitment comms[], uint64_t n) {
static C_KZG_RET compute_challenges(fr_t *out, fr_t *r_powers,
const Polynomial *polys, const g1_t *comms, uint64_t n) {
size_t i;
uint64_t j;
const size_t ni = 32; // len(FIAT_SHAMIR_PROTOCOL_DOMAIN) + 8 + 8
@ -1233,7 +1246,7 @@ static C_KZG_RET compute_challenges(BLSFieldElement *out, BLSFieldElement r_powe
hash(r_bytes, hash_input, 33);
/* Compute r_powers */
BLSFieldElement r;
fr_t r;
hash_to_bls_field(&r, r_bytes);
compute_powers(r_powers, &r, n);
@ -1247,11 +1260,11 @@ static C_KZG_RET compute_challenges(BLSFieldElement *out, BLSFieldElement r_powe
return C_KZG_OK;
}
static C_KZG_RET compute_aggregated_poly_and_commitment(Polynomial *poly_out, KZGCommitment *comm_out, BLSFieldElement *chal_out,
static C_KZG_RET compute_aggregated_poly_and_commitment(Polynomial *poly_out, g1_t *comm_out, fr_t *chal_out,
const Polynomial *polys,
const KZGCommitment *kzg_commitments,
const g1_t *kzg_commitments,
size_t n) {
BLSFieldElement* r_powers = calloc(n, sizeof(BLSFieldElement));
fr_t* r_powers = calloc(n, sizeof(fr_t));
if (0 < n && r_powers == NULL) return C_KZG_MALLOC;
C_KZG_RET ret;
@ -1273,9 +1286,9 @@ C_KZG_RET compute_aggregate_kzg_proof(KZGProof *out,
const KZGSettings *s) {
C_KZG_RET ret;
Polynomial* polys = NULL;
KZGCommitment* commitments = NULL;
g1_t* commitments = NULL;
commitments = calloc(n, sizeof(KZGCommitment));
commitments = calloc(n, sizeof(g1_t));
if (0 < n && commitments == NULL) {
ret = C_KZG_MALLOC;
goto out;
@ -1295,12 +1308,15 @@ C_KZG_RET compute_aggregate_kzg_proof(KZGProof *out,
}
Polynomial aggregated_poly;
KZGCommitment aggregated_poly_commitment;
BLSFieldElement evaluation_challenge;
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(out, &aggregated_poly, &evaluation_challenge, s);
g1_t proof;
ret = compute_kzg_proof(&proof, &aggregated_poly, &evaluation_challenge, s);
if (ret != C_KZG_OK) goto out;
bytes_from_g1((uint8_t *)(out), &proof);
out:
if (commitments != NULL) free(commitments);
@ -1315,26 +1331,46 @@ C_KZG_RET verify_aggregate_kzg_proof(bool *out,
const KZGProof *kzg_aggregated_proof,
const KZGSettings *s) {
C_KZG_RET ret;
Polynomial* polys = calloc(n, sizeof(Polynomial));
if (polys == NULL) return C_KZG_MALLOC;
g1_t* commitments = NULL;
Polynomial* polys = NULL;
g1_t proof;
ret = bytes_to_g1(&proof, (uint8_t *)(kzg_aggregated_proof));
if (ret != C_KZG_OK) goto out;
commitments = calloc(n, sizeof(g1_t));
if (0 < n && commitments == NULL) {
ret = C_KZG_MALLOC;
goto out;
}
polys = calloc(n, sizeof(Polynomial));
if (0 < n && polys == NULL) {
ret = C_KZG_MALLOC;
goto out;
}
for (size_t i = 0; i < n; i++) {
ret = bytes_to_g1(&commitments[i], (uint8_t *)(&expected_kzg_commitments[i]));
if (ret != C_KZG_OK) goto out;
ret = poly_from_blob(&polys[i], &blobs[i]);
if (ret != C_KZG_OK) goto out;
}
Polynomial aggregated_poly;
KZGCommitment aggregated_poly_commitment;
BLSFieldElement evaluation_challenge;
ret = compute_aggregated_poly_and_commitment(&aggregated_poly, &aggregated_poly_commitment, &evaluation_challenge, polys, expected_kzg_commitments, n);
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;
BLSFieldElement y;
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, kzg_aggregated_proof, s);
ret = verify_kzg_proof_impl(out, &aggregated_poly_commitment, &evaluation_challenge, &y, &proof, s);
out:
if (commitments != NULL) free(commitments);
if (polys != NULL) free(polys);
return ret;
}

View File

@ -37,16 +37,16 @@ extern "C" {
#define BYTES_PER_COMMITMENT 48
#define BYTES_PER_PROOF 48
#define BYTES_PER_FIELD_ELEMENT 32
#define BYTES_PER_BLOB FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT
#define BYTES_PER_BLOB (FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT)
static const char *FIAT_SHAMIR_PROTOCOL_DOMAIN = "FSBLOBVERIFY_V1_";
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 g1_t KZGCommitment;
typedef g1_t KZGProof;
typedef fr_t BLSFieldElement;
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;
/**
@ -82,15 +82,10 @@ typedef struct {
* Interface functions
*/
C_KZG_RET bytes_to_g1(g1_t* out, const uint8_t in[48]);
void bytes_from_g1(uint8_t out[48], const g1_t *in);
C_KZG_RET bytes_to_bls_field(BLSFieldElement *out, const uint8_t in[BYTES_PER_FIELD_ELEMENT]);
C_KZG_RET load_trusted_setup(KZGSettings *out,
const uint8_t g1_bytes[], /* n1 * 48 bytes */
const uint8_t *g1_bytes, /* n1 * 48 bytes */
size_t n1,
const uint8_t g2_bytes[], /* n2 * 96 bytes */
const uint8_t *g2_bytes, /* n2 * 96 bytes */
size_t n2);
C_KZG_RET load_trusted_setup_file(KZGSettings *out,
@ -117,8 +112,8 @@ C_KZG_RET blob_to_kzg_commitment(KZGCommitment *out,
C_KZG_RET verify_kzg_proof(bool *out,
const KZGCommitment *polynomial_kzg,
const uint8_t z[BYTES_PER_FIELD_ELEMENT],
const uint8_t y[BYTES_PER_FIELD_ELEMENT],
const BLSFieldElement *z,
const BLSFieldElement *y,
const KZGProof *kzg_proof,
const KZGSettings *s);