/ bindings / python / ckzg.c
ckzg.c
  1  #define PY_SSIZE_T_CLEAN
  2  #include <Python.h>
  3  #include "c_kzg_4844.h"
  4  
  5  static void free_KZGSettings(PyObject *c) {
  6    KZGSettings *s = PyCapsule_GetPointer(c, "KZGSettings");
  7    free_trusted_setup(s);
  8    free(s);
  9  }
 10  
 11  static PyObject* load_trusted_setup_wrap(PyObject *self, PyObject *args) {
 12    PyObject *f;
 13    FILE *fp;
 14  
 15    if (!PyArg_ParseTuple(args, "U", &f))
 16      return PyErr_Format(PyExc_ValueError, "expected a string");
 17  
 18    KZGSettings *s = (KZGSettings*)malloc(sizeof(KZGSettings));
 19    if (s == NULL) return PyErr_NoMemory();
 20  
 21    fp = fopen(PyUnicode_AsUTF8(f), "r");
 22    if (fp == NULL) {
 23      free(s);
 24      return PyErr_Format(PyExc_RuntimeError, "error reading trusted setup");
 25    }
 26  
 27    C_KZG_RET ret = load_trusted_setup_file(s, fp);
 28    fclose(fp);
 29  
 30    if (ret != C_KZG_OK) {
 31      free(s);
 32      return PyErr_Format(PyExc_RuntimeError, "error loading trusted setup");
 33    }
 34  
 35    return PyCapsule_New(s, "KZGSettings", free_KZGSettings);
 36  }
 37  
 38  static PyObject* blob_to_kzg_commitment_wrap(PyObject *self, PyObject *args) {
 39    PyObject *b;
 40    PyObject *s;
 41  
 42    if (!PyArg_UnpackTuple(args, "blob_to_kzg_commitment_wrap", 2, 2, &b, &s) ||
 43        !PyBytes_Check(b) ||
 44        !PyCapsule_IsValid(s, "KZGSettings"))
 45      return PyErr_Format(PyExc_ValueError, "expected bytes and trusted setup");
 46  
 47    if (PyBytes_Size(b) != BYTES_PER_BLOB)
 48      return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_BLOB bytes");
 49  
 50    PyObject *out = PyBytes_FromStringAndSize(NULL, BYTES_PER_COMMITMENT);
 51    if (out == NULL) return PyErr_NoMemory();
 52  
 53    Blob *blob = (Blob *)PyBytes_AsString(b);
 54    KZGCommitment *k = (KZGCommitment *)PyBytes_AsString(out);
 55    if (blob_to_kzg_commitment(k, blob, PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
 56      Py_DECREF(out);
 57      return PyErr_Format(PyExc_RuntimeError, "blob_to_kzg_commitment failed");
 58    }
 59  
 60    return out;
 61  }
 62  
 63  static PyObject* compute_kzg_proof_wrap(PyObject *self, PyObject *args) {
 64    PyObject *b, *z, *s;
 65  
 66    if (!PyArg_UnpackTuple(args, "compute_kzg_proof_wrap", 3, 3, &b, &z, &s) ||
 67        !PyBytes_Check(b) ||
 68        !PyBytes_Check(z) ||
 69        !PyCapsule_IsValid(s, "KZGSettings"))
 70      return PyErr_Format(PyExc_ValueError, "expected bytes, bytes, trusted setup");
 71  
 72    if (PyBytes_Size(b) != BYTES_PER_BLOB)
 73      return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_BLOB bytes");
 74    if (PyBytes_Size(z) != BYTES_PER_FIELD_ELEMENT)
 75      return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_FIELD_ELEMENT bytes");
 76  
 77    PyObject *py_y = PyBytes_FromStringAndSize(NULL, BYTES_PER_FIELD_ELEMENT);
 78    if (py_y == NULL) return PyErr_NoMemory();
 79    PyObject *py_proof = PyBytes_FromStringAndSize(NULL, BYTES_PER_PROOF);
 80    if (py_proof == NULL) return PyErr_NoMemory();
 81  
 82    PyObject *out = PyTuple_Pack(2, py_proof, py_y);
 83    if (out == NULL) return PyErr_NoMemory();
 84  
 85    Blob *blob = (Blob *)PyBytes_AsString(b);
 86    Bytes32 *z_bytes = (Bytes32 *)PyBytes_AsString(z);
 87    KZGProof *proof = (KZGProof *)PyBytes_AsString(py_proof);
 88    Bytes32 *y_bytes = (Bytes32 *)PyBytes_AsString(py_y);
 89    if (compute_kzg_proof(proof, y_bytes, blob, z_bytes, PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
 90      Py_DECREF(out);
 91      return PyErr_Format(PyExc_RuntimeError, "compute_kzg_proof failed");
 92    }
 93  
 94    return out;
 95  }
 96  
 97  static PyObject* compute_blob_kzg_proof_wrap(PyObject *self, PyObject *args) {
 98    PyObject *b, *c, *s;
 99  
100    if (!PyArg_UnpackTuple(args, "compute_blob_kzg_proof_wrap", 3, 3, &b, &c, &s) ||
101        !PyBytes_Check(b) ||
102        !PyBytes_Check(c) ||
103        !PyCapsule_IsValid(s, "KZGSettings"))
104      return PyErr_Format(PyExc_ValueError, "expected bytes, bytes, trusted setup");
105  
106    if (PyBytes_Size(b) != BYTES_PER_BLOB)
107      return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_BLOB bytes");
108    if (PyBytes_Size(c) != BYTES_PER_COMMITMENT)
109      return PyErr_Format(PyExc_ValueError, "expected commitment to be BYTES_PER_COMMITMENT bytes");
110  
111    PyObject *out = PyBytes_FromStringAndSize(NULL, BYTES_PER_PROOF);
112    if (out == NULL) return PyErr_NoMemory();
113  
114    Blob *blob = (Blob *)PyBytes_AsString(b);
115    Bytes48 *commitment_bytes = (Bytes48 *)PyBytes_AsString(c);
116    KZGProof *proof = (KZGProof *)PyBytes_AsString(out);
117    if (compute_blob_kzg_proof(proof, blob, commitment_bytes, PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
118      Py_DECREF(out);
119      return PyErr_Format(PyExc_RuntimeError, "compute_blob_kzg_proof failed");
120    }
121  
122    return out;
123  }
124  
125  static PyObject* verify_kzg_proof_wrap(PyObject *self, PyObject *args) {
126    PyObject *c, *z, *y, *p, *s;
127  
128    if (!PyArg_UnpackTuple(args, "verify_kzg_proof", 5, 5, &c, &z, &y, &p, &s) ||
129        !PyBytes_Check(c) ||
130        !PyBytes_Check(z) ||
131        !PyBytes_Check(y) ||
132        !PyBytes_Check(p) ||
133        !PyCapsule_IsValid(s, "KZGSettings"))
134      return PyErr_Format(PyExc_ValueError,
135          "expected bytes, bytes, bytes, bytes, trusted setup");
136  
137    if (PyBytes_Size(c) != BYTES_PER_COMMITMENT)
138      return PyErr_Format(PyExc_ValueError, "expected commitment to be BYTES_PER_COMMITMENT bytes");
139    if (PyBytes_Size(z) != BYTES_PER_FIELD_ELEMENT)
140      return PyErr_Format(PyExc_ValueError, "expected z to be BYTES_PER_FIELD_ELEMENT bytes");
141    if (PyBytes_Size(y) != BYTES_PER_FIELD_ELEMENT)
142      return PyErr_Format(PyExc_ValueError, "expected y to be BYTES_PER_FIELD_ELEMENT bytes");
143    if (PyBytes_Size(p) != BYTES_PER_PROOF)
144      return PyErr_Format(PyExc_ValueError, "expected proof to be BYTES_PER_PROOF bytes");
145  
146    const Bytes48 *commitment_bytes = (Bytes48 *)PyBytes_AsString(c);
147    const Bytes32 *z_bytes = (Bytes32 *)PyBytes_AsString(z);
148    const Bytes32 *y_bytes = (Bytes32 *)PyBytes_AsString(y);
149    const Bytes48 *proof_bytes = (Bytes48 *)PyBytes_AsString(p);
150  
151    bool ok;
152    if (verify_kzg_proof(&ok,
153          commitment_bytes, z_bytes, y_bytes, proof_bytes,
154          PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
155      return PyErr_Format(PyExc_RuntimeError, "verify_kzg_proof failed");
156    }
157  
158    if (ok) Py_RETURN_TRUE; else Py_RETURN_FALSE;
159  }
160  
161  static PyObject* verify_blob_kzg_proof_wrap(PyObject *self, PyObject *args) {
162    PyObject *b, *c, *p, *s;
163  
164    if (!PyArg_UnpackTuple(args, "verify_blob_kzg_proof", 4, 4, &b, &c, &p, &s) ||
165        !PyBytes_Check(b) ||
166        !PyBytes_Check(c) ||
167        !PyBytes_Check(p) ||
168        !PyCapsule_IsValid(s, "KZGSettings"))
169      return PyErr_Format(PyExc_ValueError,
170          "expected bytes, bytes, bytes, trusted setup");
171  
172    if (PyBytes_Size(b) != BYTES_PER_BLOB)
173      return PyErr_Format(PyExc_ValueError, "expected blob to be BYTES_PER_BLOB bytes");
174    if (PyBytes_Size(c) != BYTES_PER_COMMITMENT)
175      return PyErr_Format(PyExc_ValueError, "expected commitment to be BYTES_PER_COMMITMENT bytes");
176    if (PyBytes_Size(p) != BYTES_PER_PROOF)
177      return PyErr_Format(PyExc_ValueError, "expected proof to be BYTES_PER_PROOF bytes");
178  
179    const Blob *blob_bytes = (Blob *)PyBytes_AsString(b);
180    const Bytes48 *commitment_bytes = (Bytes48 *)PyBytes_AsString(c);
181    const Bytes48 *proof_bytes = (Bytes48 *)PyBytes_AsString(p);
182  
183    bool ok;
184    if (verify_blob_kzg_proof(&ok,
185          blob_bytes, commitment_bytes, proof_bytes,
186          PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
187      return PyErr_Format(PyExc_RuntimeError, "verify_blob_kzg_proof failed");
188    }
189  
190    if (ok) Py_RETURN_TRUE; else Py_RETURN_FALSE;
191  }
192  
193  static PyObject* verify_blob_kzg_proof_batch_wrap(PyObject *self, PyObject *args) {
194    PyObject *b, *c, *p, *s;
195  
196    if (!PyArg_UnpackTuple(args, "verify_blob_kzg_proof_batch", 4, 4, &b, &c, &p, &s) ||
197        !PyBytes_Check(b) ||
198        !PyBytes_Check(c) ||
199        !PyBytes_Check(p) ||
200        !PyCapsule_IsValid(s, "KZGSettings"))
201      return PyErr_Format(PyExc_ValueError,
202          "expected bytes, bytes, bytes, trusted setup");
203  
204    Py_ssize_t blobs_count = PyBytes_Size(b);
205    if (blobs_count % BYTES_PER_BLOB != 0)
206      return PyErr_Format(PyExc_ValueError, "expected blobs to be a multiple of BYTES_PER_BLOB bytes");
207    blobs_count = blobs_count / BYTES_PER_BLOB;
208  
209    Py_ssize_t commitments_count = PyBytes_Size(c);
210    if (commitments_count % BYTES_PER_COMMITMENT != 0)
211      return PyErr_Format(PyExc_ValueError, "expected commitments to be a multiple of BYTES_PER_COMMITMENT bytes");
212    commitments_count = commitments_count / BYTES_PER_COMMITMENT;
213  
214    Py_ssize_t proofs_count = PyBytes_Size(p);
215    if (proofs_count % BYTES_PER_PROOF != 0)
216      return PyErr_Format(PyExc_ValueError, "expected blobs to be a multiple of BYTES_PER_PROOF bytes");
217    proofs_count = proofs_count / BYTES_PER_PROOF;
218  
219    if (blobs_count != commitments_count || blobs_count != proofs_count) {
220      return PyErr_Format(PyExc_ValueError, "expected same number of blobs/commitments/proofs");
221    }
222  
223    const Blob *blobs_bytes = (Blob *)PyBytes_AsString(b);
224    const Bytes48 *commitments_bytes = (Bytes48 *)PyBytes_AsString(c);
225    const Bytes48 *proofs_bytes = (Bytes48 *)PyBytes_AsString(p);
226  
227    bool ok;
228    if (verify_blob_kzg_proof_batch(&ok,
229          blobs_bytes, commitments_bytes, proofs_bytes, blobs_count,
230          PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
231      return PyErr_Format(PyExc_RuntimeError, "verify_blob_kzg_proof_batch failed");
232    }
233  
234    if (ok) Py_RETURN_TRUE; else Py_RETURN_FALSE;
235  }
236  
237  static PyMethodDef ckzgmethods[] = {
238    {"load_trusted_setup",          load_trusted_setup_wrap,          METH_VARARGS, "Load trusted setup from file path"},
239    {"blob_to_kzg_commitment",      blob_to_kzg_commitment_wrap,      METH_VARARGS, "Create a commitment from a blob"},
240    {"compute_kzg_proof",           compute_kzg_proof_wrap,           METH_VARARGS, "Compute a proof for a blob/field"},
241    {"compute_blob_kzg_proof",      compute_blob_kzg_proof_wrap,      METH_VARARGS, "Compute a proof for a blob"},
242    {"verify_kzg_proof",            verify_kzg_proof_wrap,            METH_VARARGS, "Verify a proof for the given inputs"},
243    {"verify_blob_kzg_proof",       verify_blob_kzg_proof_wrap,       METH_VARARGS, "Verify a blob/commitment/proof combo"},
244    {"verify_blob_kzg_proof_batch", verify_blob_kzg_proof_batch_wrap, METH_VARARGS, "Verify multiple blob/commitment/proof combos"},
245    {NULL, NULL, 0, NULL}
246  };
247  
248  static struct PyModuleDef ckzg = {
249    PyModuleDef_HEAD_INIT,
250    "ckzg",
251    NULL,
252    -1,
253    ckzgmethods
254  };
255  
256  PyMODINIT_FUNC PyInit_ckzg(void) {
257      return PyModule_Create(&ckzg);
258  }