2022-10-01 23:52:12 +00:00
|
|
|
#define PY_SSIZE_T_CLEAN
|
|
|
|
#include <Python.h>
|
|
|
|
#include "c_kzg_4844.h"
|
|
|
|
|
2022-10-02 11:40:36 +00:00
|
|
|
static void free_KZGSettings(PyObject *c) {
|
|
|
|
KZGSettings *s = PyCapsule_GetPointer(c, "KZGSettings");
|
|
|
|
free_trusted_setup(s);
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* load_trusted_setup_wrap(PyObject *self, PyObject *args) {
|
|
|
|
PyObject *f;
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "U", &f))
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected a string");
|
|
|
|
|
|
|
|
KZGSettings *s = (KZGSettings*)malloc(sizeof(KZGSettings));
|
|
|
|
|
|
|
|
if (s == NULL) return PyErr_NoMemory();
|
|
|
|
|
2022-12-10 16:07:40 +00:00
|
|
|
if (load_trusted_setup_file(s, fopen(PyUnicode_AsUTF8(f), "r")) != C_KZG_OK) {
|
2022-10-02 17:36:53 +00:00
|
|
|
free(s);
|
2022-10-02 11:40:36 +00:00
|
|
|
return PyErr_Format(PyExc_RuntimeError, "error loading trusted setup");
|
2022-10-02 17:36:53 +00:00
|
|
|
}
|
2022-10-02 11:40:36 +00:00
|
|
|
|
|
|
|
return PyCapsule_New(s, "KZGSettings", free_KZGSettings);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* blob_to_kzg_commitment_wrap(PyObject *self, PyObject *args) {
|
2022-10-20 07:37:40 +00:00
|
|
|
PyObject *b;
|
|
|
|
PyObject *s;
|
2022-10-02 11:40:36 +00:00
|
|
|
|
2022-10-20 07:37:40 +00:00
|
|
|
if (!PyArg_UnpackTuple(args, "blob_to_kzg_commitment_wrap", 2, 2, &b, &s) ||
|
|
|
|
!PyBytes_Check(b) ||
|
|
|
|
!PyCapsule_IsValid(s, "KZGSettings"))
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected bytes and trusted setup");
|
2022-10-02 11:40:36 +00:00
|
|
|
|
2023-01-16 20:05:23 +00:00
|
|
|
if (PyBytes_Size(b) != BYTES_PER_BLOB)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_BLOB bytes");
|
2022-10-02 11:40:36 +00:00
|
|
|
|
2023-01-16 20:05:23 +00:00
|
|
|
PyObject *out = PyBytes_FromStringAndSize(NULL, BYTES_PER_COMMITMENT);
|
|
|
|
if (out == NULL) return PyErr_NoMemory();
|
2022-10-02 11:40:36 +00:00
|
|
|
|
2023-01-16 20:05:23 +00:00
|
|
|
Blob *blob = (Blob *)PyBytes_AsString(b);
|
|
|
|
KZGCommitment *k = (KZGCommitment *)PyBytes_AsString(out);
|
2023-01-09 17:51:05 +00:00
|
|
|
if (blob_to_kzg_commitment(k, blob, PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
|
2023-01-16 20:05:23 +00:00
|
|
|
Py_DECREF(out);
|
2023-01-09 17:51:05 +00:00
|
|
|
return PyErr_Format(PyExc_RuntimeError, "blob_to_kzg_commitment failed");
|
|
|
|
}
|
2022-10-02 11:40:36 +00:00
|
|
|
|
2023-01-16 20:05:23 +00:00
|
|
|
return out;
|
2022-10-02 11:40:36 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
static PyObject* compute_kzg_proof_wrap(PyObject *self, PyObject *args) {
|
|
|
|
PyObject *b, *z, *s;
|
|
|
|
|
|
|
|
if (!PyArg_UnpackTuple(args, "compute_kzg_proof_wrap", 3, 3, &b, &z, &s) ||
|
|
|
|
!PyBytes_Check(b) ||
|
|
|
|
!PyBytes_Check(z) ||
|
|
|
|
!PyCapsule_IsValid(s, "KZGSettings"))
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected bytes, bytes, trusted setup");
|
|
|
|
|
|
|
|
if (PyBytes_Size(b) != BYTES_PER_BLOB)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_BLOB bytes");
|
|
|
|
if (PyBytes_Size(z) != BYTES_PER_FIELD_ELEMENT)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_FIELD_ELEMENT bytes");
|
|
|
|
|
2023-03-07 19:51:43 +00:00
|
|
|
PyObject *py_y = PyBytes_FromStringAndSize(NULL, BYTES_PER_FIELD_ELEMENT);
|
|
|
|
if (py_y == NULL) return PyErr_NoMemory();
|
|
|
|
PyObject *py_proof = PyBytes_FromStringAndSize(NULL, BYTES_PER_PROOF);
|
|
|
|
if (py_proof == NULL) return PyErr_NoMemory();
|
|
|
|
|
|
|
|
PyObject *out = PyTuple_Pack(2, py_proof, py_y);
|
2023-02-20 16:00:13 +00:00
|
|
|
if (out == NULL) return PyErr_NoMemory();
|
|
|
|
|
|
|
|
Blob *blob = (Blob *)PyBytes_AsString(b);
|
|
|
|
Bytes32 *z_bytes = (Bytes32 *)PyBytes_AsString(z);
|
2023-03-07 19:51:43 +00:00
|
|
|
KZGProof *proof = (KZGProof *)PyBytes_AsString(py_proof);
|
|
|
|
Bytes32 *y_bytes = (Bytes32 *)PyBytes_AsString(py_y);
|
|
|
|
if (compute_kzg_proof(proof, y_bytes, blob, z_bytes, PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
|
2023-02-20 16:00:13 +00:00
|
|
|
Py_DECREF(out);
|
|
|
|
return PyErr_Format(PyExc_RuntimeError, "compute_kzg_proof failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* compute_blob_kzg_proof_wrap(PyObject *self, PyObject *args) {
|
2023-03-07 19:51:43 +00:00
|
|
|
PyObject *b, *c, *s;
|
2022-10-02 11:40:36 +00:00
|
|
|
|
2023-03-07 19:51:43 +00:00
|
|
|
if (!PyArg_UnpackTuple(args, "compute_blob_kzg_proof_wrap", 3, 3, &b, &c, &s) ||
|
2022-10-20 07:37:40 +00:00
|
|
|
!PyBytes_Check(b) ||
|
2023-03-07 19:51:43 +00:00
|
|
|
!PyBytes_Check(c) ||
|
2022-10-20 07:37:40 +00:00
|
|
|
!PyCapsule_IsValid(s, "KZGSettings"))
|
2023-03-07 19:51:43 +00:00
|
|
|
return PyErr_Format(PyExc_ValueError, "expected bytes, bytes, trusted setup");
|
2022-10-02 11:40:36 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
if (PyBytes_Size(b) != BYTES_PER_BLOB)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_BLOB bytes");
|
2023-03-07 19:51:43 +00:00
|
|
|
if (PyBytes_Size(c) != BYTES_PER_COMMITMENT)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected commitment to be BYTES_PER_COMMITMENT bytes");
|
2022-10-02 11:59:54 +00:00
|
|
|
|
2023-01-16 20:05:23 +00:00
|
|
|
PyObject *out = PyBytes_FromStringAndSize(NULL, BYTES_PER_PROOF);
|
|
|
|
if (out == NULL) return PyErr_NoMemory();
|
2022-10-02 11:59:54 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
Blob *blob = (Blob *)PyBytes_AsString(b);
|
2023-03-07 19:51:43 +00:00
|
|
|
Bytes48 *commitment_bytes = (Bytes48 *)PyBytes_AsString(c);
|
2023-02-20 16:00:13 +00:00
|
|
|
KZGProof *proof = (KZGProof *)PyBytes_AsString(out);
|
2023-03-07 19:51:43 +00:00
|
|
|
if (compute_blob_kzg_proof(proof, blob, commitment_bytes, PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
|
2023-01-16 20:05:23 +00:00
|
|
|
Py_DECREF(out);
|
2023-02-20 16:00:13 +00:00
|
|
|
return PyErr_Format(PyExc_RuntimeError, "compute_blob_kzg_proof failed");
|
2022-10-02 11:59:54 +00:00
|
|
|
}
|
|
|
|
|
2023-01-16 20:05:23 +00:00
|
|
|
return out;
|
2022-10-02 11:59:54 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
static PyObject* verify_kzg_proof_wrap(PyObject *self, PyObject *args) {
|
|
|
|
PyObject *c, *z, *y, *p, *s;
|
|
|
|
|
|
|
|
if (!PyArg_UnpackTuple(args, "verify_kzg_proof", 5, 5, &c, &z, &y, &p, &s) ||
|
|
|
|
!PyBytes_Check(c) ||
|
|
|
|
!PyBytes_Check(z) ||
|
|
|
|
!PyBytes_Check(y) ||
|
|
|
|
!PyBytes_Check(p) ||
|
|
|
|
!PyCapsule_IsValid(s, "KZGSettings"))
|
|
|
|
return PyErr_Format(PyExc_ValueError,
|
|
|
|
"expected bytes, bytes, bytes, bytes, trusted setup");
|
|
|
|
|
|
|
|
if (PyBytes_Size(c) != BYTES_PER_COMMITMENT)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected commitment to be BYTES_PER_COMMITMENT bytes");
|
|
|
|
if (PyBytes_Size(z) != BYTES_PER_FIELD_ELEMENT)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected z to be BYTES_PER_FIELD_ELEMENT bytes");
|
|
|
|
if (PyBytes_Size(y) != BYTES_PER_FIELD_ELEMENT)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected y to be BYTES_PER_FIELD_ELEMENT bytes");
|
|
|
|
if (PyBytes_Size(p) != BYTES_PER_PROOF)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected proof to be BYTES_PER_PROOF bytes");
|
|
|
|
|
|
|
|
const Bytes48 *commitment_bytes = (Bytes48 *)PyBytes_AsString(c);
|
|
|
|
const Bytes32 *z_bytes = (Bytes32 *)PyBytes_AsString(z);
|
|
|
|
const Bytes32 *y_bytes = (Bytes32 *)PyBytes_AsString(y);
|
|
|
|
const Bytes48 *proof_bytes = (Bytes48 *)PyBytes_AsString(p);
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
if (verify_kzg_proof(&ok,
|
|
|
|
commitment_bytes, z_bytes, y_bytes, proof_bytes,
|
|
|
|
PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
|
|
|
|
return PyErr_Format(PyExc_RuntimeError, "verify_kzg_proof failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ok) Py_RETURN_TRUE; else Py_RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* verify_blob_kzg_proof_wrap(PyObject *self, PyObject *args) {
|
2023-01-16 20:05:23 +00:00
|
|
|
PyObject *b, *c, *p, *s;
|
2022-10-02 12:21:13 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
if (!PyArg_UnpackTuple(args, "verify_blob_kzg_proof", 4, 4, &b, &c, &p, &s) ||
|
2022-10-20 07:37:40 +00:00
|
|
|
!PyBytes_Check(b) ||
|
2023-01-16 20:05:23 +00:00
|
|
|
!PyBytes_Check(c) ||
|
|
|
|
!PyBytes_Check(p) ||
|
2022-10-02 12:21:13 +00:00
|
|
|
!PyCapsule_IsValid(s, "KZGSettings"))
|
2022-10-20 07:37:40 +00:00
|
|
|
return PyErr_Format(PyExc_ValueError,
|
2023-01-16 20:05:23 +00:00
|
|
|
"expected bytes, bytes, bytes, trusted setup");
|
2022-10-02 12:21:13 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
if (PyBytes_Size(b) != BYTES_PER_BLOB)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected blob to be BYTES_PER_BLOB bytes");
|
|
|
|
if (PyBytes_Size(c) != BYTES_PER_COMMITMENT)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected commitment to be BYTES_PER_COMMITMENT bytes");
|
2023-01-16 20:05:23 +00:00
|
|
|
if (PyBytes_Size(p) != BYTES_PER_PROOF)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected proof to be BYTES_PER_PROOF bytes");
|
2022-10-02 13:01:33 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
const Blob *blob_bytes = (Blob *)PyBytes_AsString(b);
|
|
|
|
const Bytes48 *commitment_bytes = (Bytes48 *)PyBytes_AsString(c);
|
|
|
|
const Bytes48 *proof_bytes = (Bytes48 *)PyBytes_AsString(p);
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
if (verify_blob_kzg_proof(&ok,
|
|
|
|
blob_bytes, commitment_bytes, proof_bytes,
|
|
|
|
PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
|
|
|
|
return PyErr_Format(PyExc_RuntimeError, "verify_blob_kzg_proof failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ok) Py_RETURN_TRUE; else Py_RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject* verify_blob_kzg_proof_batch_wrap(PyObject *self, PyObject *args) {
|
|
|
|
PyObject *b, *c, *p, *s;
|
|
|
|
|
|
|
|
if (!PyArg_UnpackTuple(args, "verify_blob_kzg_proof_batch", 4, 4, &b, &c, &p, &s) ||
|
|
|
|
!PyBytes_Check(b) ||
|
|
|
|
!PyBytes_Check(c) ||
|
|
|
|
!PyBytes_Check(p) ||
|
|
|
|
!PyCapsule_IsValid(s, "KZGSettings"))
|
|
|
|
return PyErr_Format(PyExc_ValueError,
|
|
|
|
"expected bytes, bytes, bytes, trusted setup");
|
|
|
|
|
|
|
|
Py_ssize_t blobs_count = PyBytes_Size(b);
|
|
|
|
if (blobs_count % BYTES_PER_BLOB != 0)
|
2023-01-16 20:05:23 +00:00
|
|
|
return PyErr_Format(PyExc_ValueError, "expected blobs to be a multiple of BYTES_PER_BLOB bytes");
|
2023-02-20 16:00:13 +00:00
|
|
|
blobs_count = blobs_count / BYTES_PER_BLOB;
|
2022-10-02 13:01:33 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
Py_ssize_t commitments_count = PyBytes_Size(c);
|
|
|
|
if (commitments_count % BYTES_PER_COMMITMENT != 0)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected commitments to be a multiple of BYTES_PER_COMMITMENT bytes");
|
|
|
|
commitments_count = commitments_count / BYTES_PER_COMMITMENT;
|
2022-10-02 13:01:33 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
Py_ssize_t proofs_count = PyBytes_Size(p);
|
|
|
|
if (proofs_count % BYTES_PER_PROOF != 0)
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected blobs to be a multiple of BYTES_PER_PROOF bytes");
|
|
|
|
proofs_count = proofs_count / BYTES_PER_PROOF;
|
2022-10-02 13:01:33 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
if (blobs_count != commitments_count || blobs_count != proofs_count) {
|
|
|
|
return PyErr_Format(PyExc_ValueError, "expected same number of blobs/commitments/proofs");
|
|
|
|
}
|
|
|
|
|
|
|
|
const Blob *blobs_bytes = (Blob *)PyBytes_AsString(b);
|
2023-01-26 14:53:30 +00:00
|
|
|
const Bytes48 *commitments_bytes = (Bytes48 *)PyBytes_AsString(c);
|
2023-02-20 16:00:13 +00:00
|
|
|
const Bytes48 *proofs_bytes = (Bytes48 *)PyBytes_AsString(p);
|
2022-10-02 13:01:33 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
bool ok;
|
|
|
|
if (verify_blob_kzg_proof_batch(&ok,
|
|
|
|
blobs_bytes, commitments_bytes, proofs_bytes, blobs_count,
|
2022-10-20 07:37:40 +00:00
|
|
|
PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
|
2023-02-20 16:00:13 +00:00
|
|
|
return PyErr_Format(PyExc_RuntimeError, "verify_blob_kzg_proof_batch failed");
|
2022-10-20 07:37:40 +00:00
|
|
|
}
|
2022-10-02 13:01:33 +00:00
|
|
|
|
2023-02-20 16:00:13 +00:00
|
|
|
if (ok) Py_RETURN_TRUE; else Py_RETURN_FALSE;
|
2022-10-02 13:01:33 +00:00
|
|
|
}
|
|
|
|
|
2022-10-01 23:52:12 +00:00
|
|
|
static PyMethodDef ckzgmethods[] = {
|
2022-10-20 07:37:40 +00:00
|
|
|
{"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"},
|
2023-02-20 16:00:13 +00:00
|
|
|
{"compute_kzg_proof", compute_kzg_proof_wrap, METH_VARARGS, "Compute a proof for a blob/field"},
|
|
|
|
{"compute_blob_kzg_proof", compute_blob_kzg_proof_wrap, METH_VARARGS, "Compute a proof for a blob"},
|
|
|
|
{"verify_kzg_proof", verify_kzg_proof_wrap, METH_VARARGS, "Verify a proof for the given inputs"},
|
|
|
|
{"verify_blob_kzg_proof", verify_blob_kzg_proof_wrap, METH_VARARGS, "Verify a blob/commitment/proof combo"},
|
|
|
|
{"verify_blob_kzg_proof_batch", verify_blob_kzg_proof_batch_wrap, METH_VARARGS, "Verify multiple blob/commitment/proof combos"},
|
2022-10-01 23:52:12 +00:00
|
|
|
{NULL, NULL, 0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct PyModuleDef ckzg = {
|
|
|
|
PyModuleDef_HEAD_INIT,
|
|
|
|
"ckzg",
|
|
|
|
NULL,
|
|
|
|
-1,
|
|
|
|
ckzgmethods
|
|
|
|
};
|
|
|
|
|
2022-10-02 08:47:43 +00:00
|
|
|
PyMODINIT_FUNC PyInit_ckzg(void) {
|
2022-10-01 23:52:12 +00:00
|
|
|
return PyModule_Create(&ckzg);
|
|
|
|
}
|