mirror of
https://github.com/logos-blockchain/logos-blockchain-circuits.git
synced 2026-05-18 15:29:26 +00:00
Made API fully C-ABI-compatible.
This commit is contained in:
parent
5946705b1c
commit
dbb28502bd
103
src/ffi.cpp
103
src/ffi.cpp
@ -24,83 +24,118 @@ void qualify_input_list(std::string prefix, json& in, json& in1);
|
||||
// -------------------------------------------------------------
|
||||
|
||||
// ---- File-based entry point (wraps circom-generated main) ----
|
||||
|
||||
static status::Status validate_generate_witness_from_files_input(const char* dat, const char* inputs, const char* output) {
|
||||
if (dat == nullptr) {
|
||||
return status::Status{status::StatusCode::InvalidInput, "dat is null"};
|
||||
template<typename T>
|
||||
static Status exceptions_into_status(T&& func) {
|
||||
try {
|
||||
return func();
|
||||
} catch (const std::bad_alloc&) {
|
||||
return status_from_code(StatusCode_OutOfMemory);
|
||||
} catch (const std::exception& e) {
|
||||
return Status{StatusCode_DynError, e.what()};
|
||||
} catch (...) {
|
||||
return Status{StatusCode_DynError, "An unknown error occurred."};
|
||||
}
|
||||
if (inputs == nullptr) {
|
||||
return status::Status{status::StatusCode::InvalidInput, "inputs is null"};
|
||||
}
|
||||
if (output == nullptr) {
|
||||
return status::Status{status::StatusCode::InvalidInput, "output is null"};
|
||||
}
|
||||
return status::ok();
|
||||
}
|
||||
|
||||
extern "C" status::Status generate_witness_from_files(const char* dat, const char* inputs, const char* output) {
|
||||
const status::Status status = validate_generate_witness_from_files_input(dat, inputs, output);
|
||||
if (is_error(status)) {
|
||||
return status;
|
||||
static Status validate_generate_witness_from_files_input(const char* dat, const char* inputs, const char* output) {
|
||||
if (dat == nullptr) {
|
||||
return Status{StatusCode_InvalidInput, "dat is null"};
|
||||
}
|
||||
if (inputs == nullptr) {
|
||||
return Status{StatusCode_InvalidInput, "inputs is null"};
|
||||
}
|
||||
if (output == nullptr) {
|
||||
return Status{StatusCode_InvalidInput, "output is null"};
|
||||
}
|
||||
return status_ok();
|
||||
}
|
||||
|
||||
static Status generate_witness_from_files_impl(const char* dat, const char* inputs, const char* output) {
|
||||
char* argv[] = {
|
||||
const_cast<char*>("generate_witness_from_files"),
|
||||
const_cast<char*>(dat),
|
||||
const_cast<char*>(inputs),
|
||||
const_cast<char*>(output),
|
||||
nullptr
|
||||
};
|
||||
const int code = main(3, argv);
|
||||
|
||||
const int code = main(4, argv);
|
||||
if (code == 0) {
|
||||
return status::ok();
|
||||
return status_ok();
|
||||
}
|
||||
return status::from_code(status::StatusCode::DynError);
|
||||
return status_from_code(StatusCode_DynError);
|
||||
}
|
||||
|
||||
extern "C" Status generate_witness_from_files(const char* dat, const char* inputs, const char* output) {
|
||||
const Status status = validate_generate_witness_from_files_input(dat, inputs, output);
|
||||
if (status_is_error(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return exceptions_into_status([&] {
|
||||
return generate_witness_from_files_impl(dat, inputs, output);
|
||||
});
|
||||
}
|
||||
|
||||
// ---- Memory-based entry point ----
|
||||
|
||||
static status::Status validate_witness_input(const WitnessInput* input, const Bytes* output) {
|
||||
static Status validate_witness_input(const WitnessInput* input, const Bytes* output) {
|
||||
if (output == nullptr) {
|
||||
return status::Status{status::StatusCode::InvalidInput, "output is null"};
|
||||
return Status{StatusCode_InvalidInput, "output is null"};
|
||||
}
|
||||
if (output->data != nullptr) {
|
||||
return status::Status{status::StatusCode::InvalidInput, "output.data is not null"};
|
||||
return Status{StatusCode_InvalidInput, "output.data is not null"};
|
||||
}
|
||||
|
||||
if (input == nullptr) {
|
||||
return status::Status{status::StatusCode::InvalidInput, "input is null"};
|
||||
return Status{StatusCode_InvalidInput, "input is null"};
|
||||
}
|
||||
if (input->dat.data == nullptr) {
|
||||
return status::Status{status::StatusCode::InvalidInput, "input.dat.data is null"};
|
||||
return Status{StatusCode_InvalidInput, "input.dat.data is null"};
|
||||
}
|
||||
if (input->dat.size == 0) {
|
||||
return status::Status{status::StatusCode::InvalidInput, "input.dat.size is zero"};
|
||||
return Status{StatusCode_InvalidInput, "input.dat.size is zero"};
|
||||
}
|
||||
if (input->inputs_json == nullptr) {
|
||||
return status::Status{status::StatusCode::InvalidInput, "input.inputs_json is null"};
|
||||
return Status{StatusCode_InvalidInput, "input.inputs_json is null"};
|
||||
}
|
||||
return status::ok();
|
||||
return status_ok();
|
||||
}
|
||||
|
||||
extern "C" status::Status generate_witness(const WitnessInput* input, Bytes* output) {
|
||||
const status::Status status = validate_witness_input(input, output);
|
||||
if (is_error(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
static Status generate_witness_impl(const WitnessInput* input, Bytes* output) {
|
||||
// TODO: Implement the actual witness generation logic using the provided input data.
|
||||
const uint8_t dummy_witness[] = {0, 1, 2, 3}; // Placeholder for actual witness data
|
||||
|
||||
const size_t witness_size = sizeof(dummy_witness);
|
||||
uint8_t* witness_data = static_cast<uint8_t*>(malloc(witness_size));
|
||||
if (witness_data == nullptr) {
|
||||
return status::Status{status::StatusCode::OutOfMemory, "Failed to allocate witness memory"};
|
||||
return Status{StatusCode_OutOfMemory, "Failed to allocate witness memory"};
|
||||
}
|
||||
std::copy(dummy_witness, dummy_witness + witness_size, witness_data);
|
||||
|
||||
output->data = witness_data;
|
||||
output->size = witness_size;
|
||||
|
||||
return status::ok();
|
||||
return status_ok();
|
||||
}
|
||||
|
||||
extern "C" Status generate_witness(const WitnessInput* input, Bytes* output) {
|
||||
const Status status = validate_witness_input(input, output);
|
||||
if (status_is_error(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return exceptions_into_status([&] {
|
||||
return generate_witness_impl(input, output);
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" void free_bytes(Bytes* bytes) {
|
||||
if (bytes == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(bytes->data);
|
||||
bytes->data = nullptr;
|
||||
bytes->size = 0;
|
||||
}
|
||||
|
||||
16
src/ffi.hpp
16
src/ffi.hpp
@ -4,12 +4,12 @@
|
||||
#include "types.hpp"
|
||||
|
||||
/// Inputs for witness generation.
|
||||
struct WitnessInput {
|
||||
typedef struct WitnessInput {
|
||||
/// Contents of the circuit's .dat file.
|
||||
const ConstBytes dat;
|
||||
/// Null-terminated JSON string of circuit inputs.
|
||||
const char* inputs_json;
|
||||
};
|
||||
} WitnessInput;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -25,9 +25,9 @@ extern "C" {
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// On success, returns a `Status` with `StatusCode::Ok` and writes the witness to the specified output file.
|
||||
/// On success, returns a `Status` with `StatusCode_Ok` and writes the witness to the specified output file.
|
||||
/// On failure, returns a `Status` with an appropriate error code.
|
||||
status::Status generate_witness_from_files(const char* dat, const char* inputs, const char* output);
|
||||
Status generate_witness_from_files(const char* dat, const char* inputs, const char* output);
|
||||
|
||||
/// Generates a witness from in-memory buffers.
|
||||
///
|
||||
@ -38,10 +38,12 @@ status::Status generate_witness_from_files(const char* dat, const char* inputs,
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// On success, returns a `Status` with `StatusCode::Ok` and populates `output` with the generated witness bytes. The
|
||||
/// caller is responsible for freeing the memory allocated for `output.data`.
|
||||
/// On success, returns a `Status` with `StatusCode_Ok` and populates `output` with the generated witness bytes. The
|
||||
/// caller is responsible for freeing the resources allocated into `output` by this function using `free_bytes`.
|
||||
/// On failure, returns a `Status` with an appropriate error code, and `output` will not be modified.
|
||||
status::Status generate_witness(const WitnessInput* input, Bytes* output);
|
||||
Status generate_witness(const WitnessInput* input, Bytes* output);
|
||||
|
||||
void free_bytes(Bytes* bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -1,57 +1,54 @@
|
||||
#ifndef TYPES_HPP
|
||||
#define TYPES_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/// A pointer to a contiguous sequence of elements with a known length.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `T`: The element type. Use `const T` for immutable data.
|
||||
template<typename T>
|
||||
struct Slice {
|
||||
/// Pointer to the first element.
|
||||
T* data;
|
||||
/// Number of elements.
|
||||
size_t size;
|
||||
};
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Mutable byte buffer.
|
||||
using Bytes = Slice<uint8_t>;
|
||||
typedef struct Bytes {
|
||||
uint8_t* data;
|
||||
size_t size;
|
||||
} Bytes;
|
||||
|
||||
/// Immutable byte buffer.
|
||||
using ConstBytes = Slice<const uint8_t>;
|
||||
typedef struct ConstBytes {
|
||||
const uint8_t* data;
|
||||
size_t size;
|
||||
} ConstBytes;
|
||||
|
||||
namespace status {
|
||||
/// Represents the outcome of an operation.
|
||||
enum StatusCode {
|
||||
Ok = 0,
|
||||
DynError = 1,
|
||||
InvalidInput = 2,
|
||||
OutOfMemory = 3,
|
||||
};
|
||||
|
||||
inline bool is_ok(const StatusCode code) {
|
||||
return code == Ok;
|
||||
}
|
||||
|
||||
inline bool is_error(const StatusCode code) {
|
||||
return !is_ok(code);
|
||||
}
|
||||
|
||||
/// A status code with an optional human-readable description.
|
||||
struct Status {
|
||||
StatusCode code;
|
||||
const char* message;
|
||||
};
|
||||
|
||||
inline Status from_code(const StatusCode code) { return Status { code, nullptr }; }
|
||||
inline Status ok() { return from_code(Ok); }
|
||||
|
||||
inline bool is_ok(const Status status) { return is_ok(status.code); }
|
||||
inline bool is_error(const Status status) { return is_error(status.code); }
|
||||
typedef enum StatusCode {
|
||||
StatusCode_Ok = 0,
|
||||
StatusCode_DynError = 1,
|
||||
StatusCode_InvalidInput = 2,
|
||||
StatusCode_OutOfMemory = 3,
|
||||
} StatusCode;
|
||||
|
||||
static bool status_code_is_ok(const StatusCode code) {
|
||||
return code == StatusCode_Ok;
|
||||
}
|
||||
|
||||
static bool status_code_is_error(const StatusCode code) {
|
||||
return !status_code_is_ok(code);
|
||||
}
|
||||
|
||||
/// A status code with an optional human-readable description.
|
||||
typedef struct Status {
|
||||
StatusCode code;
|
||||
const char* message;
|
||||
} Status;
|
||||
|
||||
static Status status_from_code(const StatusCode code) { return Status { code, NULL }; }
|
||||
static Status status_ok() { return status_from_code(StatusCode_Ok); }
|
||||
|
||||
static bool status_is_ok(const Status status) { return status_code_is_ok(status.code); }
|
||||
static bool status_is_error(const Status status) { return status_code_is_error(status.code); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TYPES_HPP
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user