Packages

Ethereum EIP-4844 KZG trusted setup verification NIF bindings.

Current section

Files

Jump to
kzg_elixir c_src kzg_nif.c
Raw

c_src/kzg_nif.c

#include <erl_nif.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "ckzg.h"
#include "common/bytes.h"
// Globals for settings
KZGSettings kzg_settings;
int kzg_settings_loaded = 0;
static ERL_NIF_TERM nif_load_trusted_setup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 1) return enif_make_badarg(env);
ErlNifBinary bin;
if (!enif_inspect_binary(env, argv[0], &bin) || bin.size >= 1024) {
return enif_make_badarg(env);
}
char filename[1024];
memcpy(filename, bin.data, bin.size);
filename[bin.size] = '\0';
FILE* f = fopen(filename, "r");
if (!f) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "file_not_found"));
}
if (kzg_settings_loaded) {
free_trusted_setup(&kzg_settings);
kzg_settings_loaded = 0;
}
C_KZG_RET ret = load_trusted_setup_file(&kzg_settings, f, 0);
fclose(f);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
kzg_settings_loaded = 1;
return enif_make_atom(env, "ok");
}
static ERL_NIF_TERM nif_blob_to_kzg_commitment(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 1) return enif_make_badarg(env);
if (!kzg_settings_loaded) return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "kzg_settings_not_loaded"));
ErlNifBinary blob_bin;
if (!enif_inspect_binary(env, argv[0], &blob_bin) || blob_bin.size != BYTES_PER_BLOB) {
return enif_make_badarg(env);
}
Blob blob;
memcpy(blob.bytes, blob_bin.data, BYTES_PER_BLOB);
KZGCommitment c;
C_KZG_RET ret = blob_to_kzg_commitment(&c, &blob, &kzg_settings);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
ErlNifBinary out;
enif_alloc_binary(BYTES_PER_COMMITMENT, &out);
memcpy(out.data, c.bytes, BYTES_PER_COMMITMENT);
return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &out));
}
static ERL_NIF_TERM nif_compute_kzg_proof(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 2) return enif_make_badarg(env);
if (!kzg_settings_loaded) return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "kzg_settings_not_loaded"));
ErlNifBinary blob_bin;
ErlNifBinary z_bin;
if (!enif_inspect_binary(env, argv[0], &blob_bin) || blob_bin.size != BYTES_PER_BLOB) return enif_make_badarg(env);
if (!enif_inspect_binary(env, argv[1], &z_bin) || z_bin.size != BYTES_PER_FIELD_ELEMENT) return enif_make_badarg(env);
Blob blob;
memcpy(blob.bytes, blob_bin.data, BYTES_PER_BLOB);
Bytes32 z_bytes;
memcpy(z_bytes.bytes, z_bin.data, BYTES_PER_FIELD_ELEMENT);
KZGProof proof;
Bytes32 y;
C_KZG_RET ret = compute_kzg_proof(&proof, &y, &blob, &z_bytes, &kzg_settings);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
ErlNifBinary proof_out, y_out;
enif_alloc_binary(BYTES_PER_PROOF, &proof_out);
memcpy(proof_out.data, proof.bytes, BYTES_PER_PROOF);
enif_alloc_binary(BYTES_PER_FIELD_ELEMENT, &y_out);
memcpy(y_out.data, y.bytes, BYTES_PER_FIELD_ELEMENT);
return enif_make_tuple3(env, enif_make_atom(env, "ok"), enif_make_binary(env, &proof_out), enif_make_binary(env, &y_out));
}
static ERL_NIF_TERM nif_verify_kzg_proof(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 4) return enif_make_badarg(env);
if (!kzg_settings_loaded) return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "kzg_settings_not_loaded"));
ErlNifBinary c_bin, z_bin, y_bin, proof_bin;
if (!enif_inspect_binary(env, argv[0], &c_bin) || c_bin.size != BYTES_PER_COMMITMENT) return enif_make_badarg(env);
if (!enif_inspect_binary(env, argv[1], &z_bin) || z_bin.size != BYTES_PER_FIELD_ELEMENT) return enif_make_badarg(env);
if (!enif_inspect_binary(env, argv[2], &y_bin) || y_bin.size != BYTES_PER_FIELD_ELEMENT) return enif_make_badarg(env);
if (!enif_inspect_binary(env, argv[3], &proof_bin) || proof_bin.size != BYTES_PER_PROOF) return enif_make_badarg(env);
Bytes48 c_bytes; memcpy(c_bytes.bytes, c_bin.data, BYTES_PER_COMMITMENT);
Bytes32 z_bytes; memcpy(z_bytes.bytes, z_bin.data, BYTES_PER_FIELD_ELEMENT);
Bytes32 y_bytes; memcpy(y_bytes.bytes, y_bin.data, BYTES_PER_FIELD_ELEMENT);
Bytes48 proof_bytes; memcpy(proof_bytes.bytes, proof_bin.data, BYTES_PER_PROOF);
bool ok;
C_KZG_RET ret = verify_kzg_proof(&ok, &c_bytes, &z_bytes, &y_bytes, &proof_bytes, &kzg_settings);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
return ok ? enif_make_atom(env, "true") : enif_make_atom(env, "false");
}
static ERL_NIF_TERM nif_verify_blob_kzg_proof(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 3) return enif_make_badarg(env);
if (!kzg_settings_loaded) return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "kzg_settings_not_loaded"));
ErlNifBinary blob_bin, c_bin, proof_bin;
if (!enif_inspect_binary(env, argv[0], &blob_bin) || blob_bin.size != BYTES_PER_BLOB) return enif_make_badarg(env);
if (!enif_inspect_binary(env, argv[1], &c_bin) || c_bin.size != BYTES_PER_COMMITMENT) return enif_make_badarg(env);
if (!enif_inspect_binary(env, argv[2], &proof_bin) || proof_bin.size != BYTES_PER_PROOF) return enif_make_badarg(env);
Blob blob; memcpy(blob.bytes, blob_bin.data, BYTES_PER_BLOB);
Bytes48 c_bytes; memcpy(c_bytes.bytes, c_bin.data, BYTES_PER_COMMITMENT);
Bytes48 proof_bytes; memcpy(proof_bytes.bytes, proof_bin.data, BYTES_PER_PROOF);
bool ok;
C_KZG_RET ret = verify_blob_kzg_proof(&ok, &blob, &c_bytes, &proof_bytes, &kzg_settings);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
return ok ? enif_make_atom(env, "true") : enif_make_atom(env, "false");
}
static ERL_NIF_TERM nif_compute_blob_kzg_proof(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 2) return enif_make_badarg(env);
if (!kzg_settings_loaded)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "kzg_settings_not_loaded"));
ErlNifBinary blob_bin, c_bin;
if (!enif_inspect_binary(env, argv[0], &blob_bin) || blob_bin.size != BYTES_PER_BLOB) return enif_make_badarg(env);
if (!enif_inspect_binary(env, argv[1], &c_bin) || c_bin.size != BYTES_PER_COMMITMENT) return enif_make_badarg(env);
Blob blob; memcpy(blob.bytes, blob_bin.data, BYTES_PER_BLOB);
Bytes48 c_bytes; memcpy(c_bytes.bytes, c_bin.data, BYTES_PER_COMMITMENT);
KZGProof proof;
C_KZG_RET ret = compute_blob_kzg_proof(&proof, &blob, &c_bytes, &kzg_settings);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
ErlNifBinary proof_out;
enif_alloc_binary(BYTES_PER_PROOF, &proof_out);
memcpy(proof_out.data, proof.bytes, BYTES_PER_PROOF);
return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &proof_out));
}
static ERL_NIF_TERM nif_verify_blob_kzg_proof_batch(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 3) return enif_make_badarg(env);
if (!kzg_settings_loaded)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "kzg_settings_not_loaded"));
ERL_NIF_TERM blobs_list = argv[0];
ERL_NIF_TERM commitments_list = argv[1];
ERL_NIF_TERM proofs_list = argv[2];
unsigned int n_blobs, n_commitments, n_proofs;
if (!enif_get_list_length(env, blobs_list, &n_blobs)) return enif_make_badarg(env);
if (!enif_get_list_length(env, commitments_list, &n_commitments)) return enif_make_badarg(env);
if (!enif_get_list_length(env, proofs_list, &n_proofs)) return enif_make_badarg(env);
if (n_blobs != n_commitments || n_blobs != n_proofs) return enif_make_badarg(env);
uint64_t n = (uint64_t)n_blobs;
Blob* blobs = (Blob*)enif_alloc(sizeof(Blob) * n);
Bytes48* commitments = (Bytes48*)enif_alloc(sizeof(Bytes48) * n);
Bytes48* proofs = (Bytes48*)enif_alloc(sizeof(Bytes48) * n);
if (!blobs || !commitments || !proofs) {
if (blobs) enif_free(blobs);
if (commitments) enif_free(commitments);
if (proofs) enif_free(proofs);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "alloc_failed"));
}
ERL_NIF_TERM head, tail;
unsigned int i = 0;
// blobs
tail = blobs_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_BLOB) {
enif_free(blobs); enif_free(commitments); enif_free(proofs);
return enif_make_badarg(env);
}
memcpy(blobs[i].bytes, bin.data, BYTES_PER_BLOB);
i++;
}
// commitments
i = 0;
tail = commitments_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_COMMITMENT) {
enif_free(blobs); enif_free(commitments); enif_free(proofs);
return enif_make_badarg(env);
}
memcpy(commitments[i].bytes, bin.data, BYTES_PER_COMMITMENT);
i++;
}
// proofs
i = 0;
tail = proofs_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_PROOF) {
enif_free(blobs); enif_free(commitments); enif_free(proofs);
return enif_make_badarg(env);
}
memcpy(proofs[i].bytes, bin.data, BYTES_PER_PROOF);
i++;
}
bool ok;
C_KZG_RET ret = verify_blob_kzg_proof_batch(&ok, blobs, commitments, proofs, n, &kzg_settings);
enif_free(blobs);
enif_free(commitments);
enif_free(proofs);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
return enif_make_tuple2(env, enif_make_atom(env, "ok"), ok ? enif_make_atom(env, "true") : enif_make_atom(env, "false"));
}
static ERL_NIF_TERM nif_compute_challenge(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 2) return enif_make_badarg(env);
ErlNifBinary blob_bin, c_bin;
if (!enif_inspect_binary(env, argv[0], &blob_bin) || blob_bin.size != BYTES_PER_BLOB) return enif_make_badarg(env);
if (!enif_inspect_binary(env, argv[1], &c_bin) || c_bin.size != BYTES_PER_COMMITMENT) return enif_make_badarg(env);
Blob blob; memcpy(blob.bytes, blob_bin.data, BYTES_PER_BLOB);
Bytes48 c_bytes; memcpy(c_bytes.bytes, c_bin.data, BYTES_PER_COMMITMENT);
g1_t commitment;
if (bytes_to_kzg_commitment(&commitment, &c_bytes) != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, C_KZG_BADARGS));
}
fr_t challenge;
compute_challenge(&challenge, &blob, &commitment);
Bytes32 out;
bytes_from_bls_field(&out, &challenge);
ErlNifBinary out_bin;
enif_alloc_binary(BYTES_PER_FIELD_ELEMENT, &out_bin);
memcpy(out_bin.data, out.bytes, BYTES_PER_FIELD_ELEMENT);
return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &out_bin));
}
static ERL_NIF_TERM nif_compute_cells_and_kzg_proofs(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 1) return enif_make_badarg(env);
if (!kzg_settings_loaded)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "kzg_settings_not_loaded"));
ErlNifBinary blob_bin;
if (!enif_inspect_binary(env, argv[0], &blob_bin) || blob_bin.size != BYTES_PER_BLOB) return enif_make_badarg(env);
Blob blob; memcpy(blob.bytes, blob_bin.data, BYTES_PER_BLOB);
Cell cells[CELLS_PER_EXT_BLOB];
KZGProof proofs[CELLS_PER_EXT_BLOB];
C_KZG_RET ret = compute_cells_and_kzg_proofs(cells, proofs, &blob, &kzg_settings);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
ERL_NIF_TERM* cell_terms = (ERL_NIF_TERM*)enif_alloc(sizeof(ERL_NIF_TERM) * CELLS_PER_EXT_BLOB);
ERL_NIF_TERM* proof_terms = (ERL_NIF_TERM*)enif_alloc(sizeof(ERL_NIF_TERM) * CELLS_PER_EXT_BLOB);
if (!cell_terms || !proof_terms) {
if (cell_terms) enif_free(cell_terms);
if (proof_terms) enif_free(proof_terms);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "alloc_failed"));
}
for (size_t i = 0; i < CELLS_PER_EXT_BLOB; i++) {
ErlNifBinary cell_out;
enif_alloc_binary(BYTES_PER_CELL, &cell_out);
memcpy(cell_out.data, cells[i].bytes, BYTES_PER_CELL);
cell_terms[i] = enif_make_binary(env, &cell_out);
ErlNifBinary proof_out;
enif_alloc_binary(BYTES_PER_PROOF, &proof_out);
memcpy(proof_out.data, proofs[i].bytes, BYTES_PER_PROOF);
proof_terms[i] = enif_make_binary(env, &proof_out);
}
ERL_NIF_TERM cells_list = enif_make_list_from_array(env, cell_terms, CELLS_PER_EXT_BLOB);
ERL_NIF_TERM proofs_list = enif_make_list_from_array(env, proof_terms, CELLS_PER_EXT_BLOB);
enif_free(cell_terms);
enif_free(proof_terms);
return enif_make_tuple3(env, enif_make_atom(env, "ok"), cells_list, proofs_list);
}
static ERL_NIF_TERM nif_recover_cells_and_kzg_proofs(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 2) return enif_make_badarg(env);
if (!kzg_settings_loaded)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "kzg_settings_not_loaded"));
ERL_NIF_TERM indices_list = argv[0];
ERL_NIF_TERM cells_list = argv[1];
unsigned int n_indices, n_cells;
if (!enif_get_list_length(env, indices_list, &n_indices)) return enif_make_badarg(env);
if (!enif_get_list_length(env, cells_list, &n_cells)) return enif_make_badarg(env);
if (n_indices != n_cells) return enif_make_badarg(env);
if (n_cells > CELLS_PER_EXT_BLOB) return enif_make_badarg(env);
uint64_t* cell_indices = (uint64_t*)enif_alloc(sizeof(uint64_t) * n_cells);
Cell* cells = (Cell*)enif_alloc(sizeof(Cell) * n_cells);
if (!cell_indices || !cells) {
if (cell_indices) enif_free(cell_indices);
if (cells) enif_free(cells);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "alloc_failed"));
}
ERL_NIF_TERM head, tail;
unsigned int i = 0;
tail = indices_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
unsigned long idx;
if (!enif_get_ulong(env, head, &idx)) {
enif_free(cell_indices); enif_free(cells);
return enif_make_badarg(env);
}
cell_indices[i++] = (uint64_t)idx;
}
i = 0;
tail = cells_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_CELL) {
enif_free(cell_indices); enif_free(cells);
return enif_make_badarg(env);
}
memcpy(cells[i].bytes, bin.data, BYTES_PER_CELL);
i++;
}
Cell recovered_cells[CELLS_PER_EXT_BLOB];
KZGProof recovered_proofs[CELLS_PER_EXT_BLOB];
C_KZG_RET ret =
recover_cells_and_kzg_proofs(recovered_cells, recovered_proofs, cell_indices, cells, (uint64_t)n_cells, &kzg_settings);
enif_free(cell_indices);
enif_free(cells);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
ERL_NIF_TERM* cell_terms = (ERL_NIF_TERM*)enif_alloc(sizeof(ERL_NIF_TERM) * CELLS_PER_EXT_BLOB);
ERL_NIF_TERM* proof_terms = (ERL_NIF_TERM*)enif_alloc(sizeof(ERL_NIF_TERM) * CELLS_PER_EXT_BLOB);
if (!cell_terms || !proof_terms) {
if (cell_terms) enif_free(cell_terms);
if (proof_terms) enif_free(proof_terms);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "alloc_failed"));
}
for (size_t j = 0; j < CELLS_PER_EXT_BLOB; j++) {
ErlNifBinary cell_out;
enif_alloc_binary(BYTES_PER_CELL, &cell_out);
memcpy(cell_out.data, recovered_cells[j].bytes, BYTES_PER_CELL);
cell_terms[j] = enif_make_binary(env, &cell_out);
ErlNifBinary proof_out;
enif_alloc_binary(BYTES_PER_PROOF, &proof_out);
memcpy(proof_out.data, recovered_proofs[j].bytes, BYTES_PER_PROOF);
proof_terms[j] = enif_make_binary(env, &proof_out);
}
ERL_NIF_TERM out_cells_list = enif_make_list_from_array(env, cell_terms, CELLS_PER_EXT_BLOB);
ERL_NIF_TERM out_proofs_list = enif_make_list_from_array(env, proof_terms, CELLS_PER_EXT_BLOB);
enif_free(cell_terms);
enif_free(proof_terms);
return enif_make_tuple3(env, enif_make_atom(env, "ok"), out_cells_list, out_proofs_list);
}
static ERL_NIF_TERM nif_verify_cell_kzg_proof_batch(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 4) return enif_make_badarg(env);
if (!kzg_settings_loaded)
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "kzg_settings_not_loaded"));
ERL_NIF_TERM commitments_list = argv[0];
ERL_NIF_TERM indices_list = argv[1];
ERL_NIF_TERM cells_list = argv[2];
ERL_NIF_TERM proofs_list = argv[3];
unsigned int n_commitments, n_indices, n_cells, n_proofs;
if (!enif_get_list_length(env, commitments_list, &n_commitments)) return enif_make_badarg(env);
if (!enif_get_list_length(env, indices_list, &n_indices)) return enif_make_badarg(env);
if (!enif_get_list_length(env, cells_list, &n_cells)) return enif_make_badarg(env);
if (!enif_get_list_length(env, proofs_list, &n_proofs)) return enif_make_badarg(env);
if (n_commitments != n_indices || n_commitments != n_cells || n_commitments != n_proofs) return enif_make_badarg(env);
uint64_t n = (uint64_t)n_cells;
Bytes48* commitments = (Bytes48*)enif_alloc(sizeof(Bytes48) * n);
uint64_t* cell_indices = (uint64_t*)enif_alloc(sizeof(uint64_t) * n);
Cell* cells = (Cell*)enif_alloc(sizeof(Cell) * n);
Bytes48* proofs = (Bytes48*)enif_alloc(sizeof(Bytes48) * n);
if (!commitments || !cell_indices || !cells || !proofs) {
if (commitments) enif_free(commitments);
if (cell_indices) enif_free(cell_indices);
if (cells) enif_free(cells);
if (proofs) enif_free(proofs);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "alloc_failed"));
}
ERL_NIF_TERM head, tail;
unsigned int i = 0;
tail = commitments_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_COMMITMENT) {
enif_free(commitments); enif_free(cell_indices); enif_free(cells); enif_free(proofs);
return enif_make_badarg(env);
}
memcpy(commitments[i].bytes, bin.data, BYTES_PER_COMMITMENT);
i++;
}
i = 0;
tail = indices_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
unsigned long idx;
if (!enif_get_ulong(env, head, &idx)) {
enif_free(commitments); enif_free(cell_indices); enif_free(cells); enif_free(proofs);
return enif_make_badarg(env);
}
cell_indices[i++] = (uint64_t)idx;
}
i = 0;
tail = cells_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_CELL) {
enif_free(commitments); enif_free(cell_indices); enif_free(cells); enif_free(proofs);
return enif_make_badarg(env);
}
memcpy(cells[i].bytes, bin.data, BYTES_PER_CELL);
i++;
}
i = 0;
tail = proofs_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_PROOF) {
enif_free(commitments); enif_free(cell_indices); enif_free(cells); enif_free(proofs);
return enif_make_badarg(env);
}
memcpy(proofs[i].bytes, bin.data, BYTES_PER_PROOF);
i++;
}
bool ok;
C_KZG_RET ret = verify_cell_kzg_proof_batch(&ok, commitments, cell_indices, cells, proofs, n, &kzg_settings);
enif_free(commitments);
enif_free(cell_indices);
enif_free(cells);
enif_free(proofs);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
return enif_make_tuple2(env, enif_make_atom(env, "ok"), ok ? enif_make_atom(env, "true") : enif_make_atom(env, "false"));
}
static ERL_NIF_TERM nif_compute_verify_cell_kzg_proof_batch_challenge(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
if (argc != 5) return enif_make_badarg(env);
ERL_NIF_TERM commitments_list = argv[0];
ERL_NIF_TERM commitment_indices_list = argv[1];
ERL_NIF_TERM cell_indices_list = argv[2];
ERL_NIF_TERM cells_list = argv[3];
ERL_NIF_TERM proofs_list = argv[4];
unsigned int num_commitments, num_commitment_indices, num_cell_indices, num_cells, num_proofs;
if (!enif_get_list_length(env, commitments_list, &num_commitments)) return enif_make_badarg(env);
if (!enif_get_list_length(env, commitment_indices_list, &num_commitment_indices)) return enif_make_badarg(env);
if (!enif_get_list_length(env, cell_indices_list, &num_cell_indices)) return enif_make_badarg(env);
if (!enif_get_list_length(env, cells_list, &num_cells)) return enif_make_badarg(env);
if (!enif_get_list_length(env, proofs_list, &num_proofs)) return enif_make_badarg(env);
if (num_commitment_indices != num_cells || num_cell_indices != num_cells || num_proofs != num_cells) return enif_make_badarg(env);
Bytes48* commitments = (Bytes48*)enif_alloc(sizeof(Bytes48) * num_commitments);
uint64_t* commitment_indices = (uint64_t*)enif_alloc(sizeof(uint64_t) * num_cells);
uint64_t* cell_indices = (uint64_t*)enif_alloc(sizeof(uint64_t) * num_cells);
Cell* cells = (Cell*)enif_alloc(sizeof(Cell) * num_cells);
Bytes48* proofs = (Bytes48*)enif_alloc(sizeof(Bytes48) * num_cells);
if (!commitments || !commitment_indices || !cell_indices || !cells || !proofs) {
if (commitments) enif_free(commitments);
if (commitment_indices) enif_free(commitment_indices);
if (cell_indices) enif_free(cell_indices);
if (cells) enif_free(cells);
if (proofs) enif_free(proofs);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "alloc_failed"));
}
ERL_NIF_TERM head, tail;
unsigned int i = 0;
tail = commitments_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_COMMITMENT) {
enif_free(commitments); enif_free(commitment_indices); enif_free(cell_indices); enif_free(cells); enif_free(proofs);
return enif_make_badarg(env);
}
memcpy(commitments[i].bytes, bin.data, BYTES_PER_COMMITMENT);
i++;
}
i = 0;
tail = commitment_indices_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
unsigned long idx;
if (!enif_get_ulong(env, head, &idx)) {
enif_free(commitments); enif_free(commitment_indices); enif_free(cell_indices); enif_free(cells); enif_free(proofs);
return enif_make_badarg(env);
}
commitment_indices[i++] = (uint64_t)idx;
}
i = 0;
tail = cell_indices_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
unsigned long idx;
if (!enif_get_ulong(env, head, &idx)) {
enif_free(commitments); enif_free(commitment_indices); enif_free(cell_indices); enif_free(cells); enif_free(proofs);
return enif_make_badarg(env);
}
cell_indices[i++] = (uint64_t)idx;
}
i = 0;
tail = cells_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_CELL) {
enif_free(commitments); enif_free(commitment_indices); enif_free(cell_indices); enif_free(cells); enif_free(proofs);
return enif_make_badarg(env);
}
memcpy(cells[i].bytes, bin.data, BYTES_PER_CELL);
i++;
}
i = 0;
tail = proofs_list;
while (enif_get_list_cell(env, tail, &head, &tail)) {
ErlNifBinary bin;
if (!enif_inspect_binary(env, head, &bin) || bin.size != BYTES_PER_PROOF) {
enif_free(commitments); enif_free(commitment_indices); enif_free(cell_indices); enif_free(cells); enif_free(proofs);
return enif_make_badarg(env);
}
memcpy(proofs[i].bytes, bin.data, BYTES_PER_PROOF);
i++;
}
fr_t challenge;
C_KZG_RET ret = compute_verify_cell_kzg_proof_batch_challenge(
&challenge,
commitments,
(uint64_t)num_commitments,
commitment_indices,
cell_indices,
cells,
proofs,
(uint64_t)num_cells
);
enif_free(commitments);
enif_free(commitment_indices);
enif_free(cell_indices);
enif_free(cells);
enif_free(proofs);
if (ret != C_KZG_OK) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, ret));
}
Bytes32 out;
bytes_from_bls_field(&out, &challenge);
ErlNifBinary out_bin;
enif_alloc_binary(BYTES_PER_FIELD_ELEMENT, &out_bin);
memcpy(out_bin.data, out.bytes, BYTES_PER_FIELD_ELEMENT);
return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &out_bin));
}
static ErlNifFunc nif_funcs[] = {
{"load_trusted_setup", 1, nif_load_trusted_setup, 0},
{"blob_to_kzg_commitment", 1, nif_blob_to_kzg_commitment, 0},
{"compute_kzg_proof", 2, nif_compute_kzg_proof, 0},
{"verify_kzg_proof", 4, nif_verify_kzg_proof, 0},
{"verify_blob_kzg_proof", 3, nif_verify_blob_kzg_proof, 0},
{"compute_blob_kzg_proof", 2, nif_compute_blob_kzg_proof, 0},
{"verify_blob_kzg_proof_batch", 3, nif_verify_blob_kzg_proof_batch, 0},
{"compute_challenge", 2, nif_compute_challenge, 0},
{"compute_cells_and_kzg_proofs", 1, nif_compute_cells_and_kzg_proofs, 0},
{"recover_cells_and_kzg_proofs", 2, nif_recover_cells_and_kzg_proofs, 0},
{"verify_cell_kzg_proof_batch", 4, nif_verify_cell_kzg_proof_batch, 0},
{"compute_verify_cell_kzg_proof_batch_challenge", 5, nif_compute_verify_cell_kzg_proof_batch_challenge, 0}
};
ERL_NIF_INIT(Elixir.KzgElixir, nif_funcs, NULL, NULL, NULL, NULL)