Update python bindings (#145)
This commit is contained in:
parent
46d529cf00
commit
daa5f79fe3
|
@ -51,37 +51,98 @@ static PyObject* blob_to_kzg_commitment_wrap(PyObject *self, PyObject *args) {
|
|||
return out;
|
||||
}
|
||||
|
||||
static PyObject* compute_aggregate_kzg_proof_wrap(PyObject *self, PyObject *args) {
|
||||
PyObject *b, *s;
|
||||
static PyObject* compute_kzg_proof_wrap(PyObject *self, PyObject *args) {
|
||||
PyObject *b, *z, *s;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "compute_aggregate_kzg_proof", 2, 2, &b, &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, trusted setup");
|
||||
return PyErr_Format(PyExc_ValueError, "expected bytes, bytes, trusted setup");
|
||||
|
||||
Py_ssize_t n = PyBytes_Size(b);
|
||||
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 (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");
|
||||
|
||||
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) {
|
||||
Blob *blob = (Blob *)PyBytes_AsString(b);
|
||||
Bytes32 *z_bytes = (Bytes32 *)PyBytes_AsString(z);
|
||||
KZGProof *proof = (KZGProof *)PyBytes_AsString(out);
|
||||
if (compute_kzg_proof(proof, blob, z_bytes, PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
|
||||
Py_DECREF(out);
|
||||
return PyErr_Format(PyExc_RuntimeError, "compute_aggregate_kzg_proof failed");
|
||||
return PyErr_Format(PyExc_RuntimeError, "compute_kzg_proof failed");
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static PyObject* verify_aggregate_kzg_proof_wrap(PyObject *self, PyObject *args) {
|
||||
static PyObject* compute_blob_kzg_proof_wrap(PyObject *self, PyObject *args) {
|
||||
PyObject *b, *s;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "compute_kzg_proof_wrap", 2, 2, &b, &s) ||
|
||||
!PyBytes_Check(b) ||
|
||||
!PyCapsule_IsValid(s, "KZGSettings"))
|
||||
return PyErr_Format(PyExc_ValueError, "expected bytes, trusted setup");
|
||||
|
||||
if (PyBytes_Size(b) != BYTES_PER_BLOB)
|
||||
return PyErr_Format(PyExc_ValueError, "expected blobs to be BYTES_PER_BLOB bytes");
|
||||
|
||||
PyObject *out = PyBytes_FromStringAndSize(NULL, BYTES_PER_PROOF);
|
||||
if (out == NULL) return PyErr_NoMemory();
|
||||
|
||||
Blob *blob = (Blob *)PyBytes_AsString(b);
|
||||
KZGProof *proof = (KZGProof *)PyBytes_AsString(out);
|
||||
if (compute_blob_kzg_proof(proof, blob, PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
|
||||
Py_DECREF(out);
|
||||
return PyErr_Format(PyExc_RuntimeError, "compute_blob_kzg_proof failed");
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
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) {
|
||||
PyObject *b, *c, *p, *s;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "verify_aggregate_kzg_proof", 4, 4, &b, &c, &p, &s) ||
|
||||
if (!PyArg_UnpackTuple(args, "verify_blob_kzg_proof", 4, 4, &b, &c, &p, &s) ||
|
||||
!PyBytes_Check(b) ||
|
||||
!PyBytes_Check(c) ||
|
||||
!PyBytes_Check(p) ||
|
||||
|
@ -89,41 +150,79 @@ static PyObject* verify_aggregate_kzg_proof_wrap(PyObject *self, PyObject *args)
|
|||
return PyErr_Format(PyExc_ValueError,
|
||||
"expected bytes, bytes, bytes, trusted setup");
|
||||
|
||||
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");
|
||||
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 % 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;
|
||||
|
||||
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");
|
||||
|
||||
const Blob* blobs = (Blob *)PyBytes_AsString(b);
|
||||
const Blob *blob_bytes = (Blob *)PyBytes_AsString(b);
|
||||
const Bytes48 *commitment_bytes = (Bytes48 *)PyBytes_AsString(c);
|
||||
const Bytes48 *proof_bytes = (Bytes48 *)PyBytes_AsString(p);
|
||||
const Bytes48 *commitments_bytes = (Bytes48 *)PyBytes_AsString(c);
|
||||
|
||||
bool out;
|
||||
if (verify_aggregate_kzg_proof(&out,
|
||||
blobs, commitments_bytes, n, proof_bytes,
|
||||
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_aggregate_kzg_proof failed");
|
||||
return PyErr_Format(PyExc_RuntimeError, "verify_blob_kzg_proof failed");
|
||||
}
|
||||
|
||||
if (out) Py_RETURN_TRUE; else Py_RETURN_FALSE;
|
||||
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)
|
||||
return PyErr_Format(PyExc_ValueError, "expected blobs to be a multiple of BYTES_PER_BLOB bytes");
|
||||
blobs_count = blobs_count / BYTES_PER_BLOB;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
const Bytes48 *commitments_bytes = (Bytes48 *)PyBytes_AsString(c);
|
||||
const Bytes48 *proofs_bytes = (Bytes48 *)PyBytes_AsString(p);
|
||||
|
||||
bool ok;
|
||||
if (verify_blob_kzg_proof_batch(&ok,
|
||||
blobs_bytes, commitments_bytes, proofs_bytes, blobs_count,
|
||||
PyCapsule_GetPointer(s, "KZGSettings")) != C_KZG_OK) {
|
||||
return PyErr_Format(PyExc_RuntimeError, "verify_blob_kzg_proof_batch failed");
|
||||
}
|
||||
|
||||
if (ok) Py_RETURN_TRUE; else Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
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"},
|
||||
{"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"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,36 +1,128 @@
|
|||
import glob
|
||||
from os.path import join
|
||||
from os.path import isfile
|
||||
|
||||
import ckzg
|
||||
import random
|
||||
|
||||
# Commit to a few random blobs
|
||||
###############################################################################
|
||||
# Constants
|
||||
###############################################################################
|
||||
|
||||
BLOB_SIZE = 4096
|
||||
MAX_BLOBS_PER_BLOCK = 16
|
||||
blob_to_kzg_commitment_tests = "../../tests/blob_to_kzg_commitment/*"
|
||||
compute_kzg_proof_tests = "../../tests/compute_kzg_proof/*"
|
||||
compute_blob_kzg_proof_tests = "../../tests/compute_blob_kzg_proof/*"
|
||||
verify_kzg_proof_tests = "../../tests/verify_kzg_proof/*"
|
||||
verify_blob_kzg_proof_tests = "../../tests/verify_blob_kzg_proof/*"
|
||||
verify_blob_kzg_proof_batch_tests = "../../tests/verify_blob_kzg_proof_batch/*"
|
||||
|
||||
blobs = [
|
||||
# use zero final bytes to easily ensure the encodings are valid
|
||||
b''.join([b''.join([random.randbytes(31), bytes(1)]) for _ in range(BLOB_SIZE)])
|
||||
for _ in range(3)
|
||||
]
|
||||
###############################################################################
|
||||
# Helper Functions
|
||||
###############################################################################
|
||||
|
||||
ts = ckzg.load_trusted_setup("../../src/trusted_setup.txt")
|
||||
def get_blob(path):
|
||||
with open(path, "r") as f:
|
||||
return bytes.fromhex(f.read())
|
||||
|
||||
kzg_commitments = b''.join([ckzg.blob_to_kzg_commitment(blob, ts) for blob in blobs])
|
||||
def get_bytes32(path):
|
||||
with open(path, "r") as f:
|
||||
return bytes.fromhex(f.read())
|
||||
|
||||
# Compute proof for these blobs
|
||||
def get_bytes48(path):
|
||||
with open(path, "r") as f:
|
||||
return bytes.fromhex(f.read())
|
||||
|
||||
blobs_bytes = b''.join(blobs)
|
||||
def get_boolean(path):
|
||||
with open(path, "r") as f:
|
||||
return "true" in f.read()
|
||||
|
||||
proof = ckzg.compute_aggregate_kzg_proof(blobs_bytes, ts)
|
||||
###############################################################################
|
||||
# Tests
|
||||
###############################################################################
|
||||
|
||||
# Verify proof
|
||||
def test_blob_to_kzg_commitment(ts):
|
||||
for test in glob.glob(blob_to_kzg_commitment_tests):
|
||||
blob = get_blob(join(test, "blob.txt"))
|
||||
try:
|
||||
commitment = ckzg.blob_to_kzg_commitment(blob, ts)
|
||||
expected_commitment = get_bytes48(join(test, "commitment.txt"))
|
||||
assert commitment == expected_commitment
|
||||
except:
|
||||
assert not isfile(join(test, "commitment.txt"))
|
||||
|
||||
assert ckzg.verify_aggregate_kzg_proof(blobs_bytes, kzg_commitments, proof, ts), 'verify failed'
|
||||
def test_compute_kzg_proof(ts):
|
||||
for test in glob.glob(compute_kzg_proof_tests):
|
||||
blob = get_blob(join(test, "blob.txt"))
|
||||
input_point = get_bytes32(join(test, "input_point.txt"))
|
||||
try:
|
||||
proof = ckzg.compute_kzg_proof(blob, input_point, ts)
|
||||
expected_proof = get_bytes48(join(test, "proof.txt"))
|
||||
assert proof == expected_proof
|
||||
except:
|
||||
assert not isfile(join(test, "proof.txt"))
|
||||
|
||||
# Verification fails at wrong value
|
||||
def test_compute_blob_kzg_proof(ts):
|
||||
for test in glob.glob(compute_blob_kzg_proof_tests):
|
||||
blob = get_blob(join(test, "blob.txt"))
|
||||
try:
|
||||
proof = ckzg.compute_blob_kzg_proof(blob, ts)
|
||||
expected_proof = get_bytes48(join(test, "proof.txt"))
|
||||
assert proof == expected_proof
|
||||
except:
|
||||
assert not isfile(join(test, "proof.txt"))
|
||||
|
||||
other = b'x' if not blobs_bytes.startswith(b'x') else b'y'
|
||||
other_bytes = other + blobs_bytes[1:]
|
||||
def test_verify_kzg_proof(ts):
|
||||
for test in glob.glob(verify_kzg_proof_tests):
|
||||
commitment = get_bytes48(join(test, "commitment.txt"))
|
||||
input_point = get_bytes32(join(test, "input_point.txt"))
|
||||
claimed_value = get_bytes32(join(test, "claimed_value.txt"))
|
||||
proof = get_bytes48(join(test, "proof.txt"))
|
||||
try:
|
||||
ok = ckzg.verify_kzg_proof(commitment, input_point, claimed_value, proof, ts)
|
||||
expected_ok = get_boolean(join(test, "ok.txt"))
|
||||
assert ok == expected_ok
|
||||
except:
|
||||
assert not isfile(join(test, "ok.txt"))
|
||||
|
||||
assert not ckzg.verify_aggregate_kzg_proof(other_bytes, kzg_commitments, proof, ts), 'verify succeeded incorrectly'
|
||||
def test_verify_blob_kzg_proof(ts):
|
||||
for test in glob.glob(verify_blob_kzg_proof_tests):
|
||||
blob = get_bytes32(join(test, "blob.txt"))
|
||||
commitment = get_bytes48(join(test, "commitment.txt"))
|
||||
proof = get_bytes48(join(test, "proof.txt"))
|
||||
try:
|
||||
ok = ckzg.verify_blob_kzg_proof(blob, commitment, proof, ts)
|
||||
expected_ok = get_boolean(join(test, "ok.txt"))
|
||||
assert ok == expected_ok
|
||||
except:
|
||||
assert not isfile(join(test, "ok.txt"))
|
||||
|
||||
print('tests passed')
|
||||
def test_verify_blob_kzg_proof_batch(ts):
|
||||
for test in glob.glob(verify_blob_kzg_proof_batch_tests):
|
||||
blob_files = sorted(glob.glob(join(test, "blobs/*")))
|
||||
blobs = b"".join([get_blob(b) for b in blob_files])
|
||||
commitment_files = sorted(glob.glob(join(test, "commitments/*")))
|
||||
commitments = b"".join([get_bytes48(c) for c in commitment_files])
|
||||
proof_files = sorted(glob.glob(join(test, "proofs/*")))
|
||||
proofs = b"".join([get_bytes48(p) for p in proof_files])
|
||||
|
||||
try:
|
||||
ok = ckzg.verify_blob_kzg_proof_batch(blobs, commitments, proofs, ts)
|
||||
expected_ok = get_boolean(join(test, "ok.txt"))
|
||||
assert ok == expected_ok
|
||||
except:
|
||||
assert not isfile(join(test, "ok.txt"))
|
||||
|
||||
###############################################################################
|
||||
# Main Logic
|
||||
###############################################################################
|
||||
|
||||
if __name__ == "__main__":
|
||||
ts = ckzg.load_trusted_setup("../../src/trusted_setup.txt")
|
||||
|
||||
test_blob_to_kzg_commitment(ts)
|
||||
test_compute_kzg_proof(ts)
|
||||
test_compute_blob_kzg_proof(ts)
|
||||
test_verify_kzg_proof(ts)
|
||||
test_verify_blob_kzg_proof(ts)
|
||||
test_verify_blob_kzg_proof_batch(ts)
|
||||
|
||||
print('tests passed')
|
||||
|
|
Loading…
Reference in New Issue