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 }