Remove incompatible C ABI things.

This commit is contained in:
Alejandro Cabeza Romero 2026-04-10 15:05:29 +02:00
parent 505048bc3b
commit 5946705b1c
No known key found for this signature in database
GPG Key ID: DA3D14AE478030FD
3 changed files with 111 additions and 71 deletions

View File

@ -2,6 +2,8 @@
#include <string>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <nlohmann/json.hpp>
@ -19,21 +21,86 @@ json::value_t check_type(std::string prefix, json in);
void qualify_input(std::string prefix, json& in, json& in1);
void qualify_input_list(std::string prefix, json& in, json& in1);
// -------------------------------------------------------------
// ---- File-based entry point (wraps circom-generated main) ----
extern "C" int generate_witness_from_files(const char* dat, const char* inputs, const char* output) {
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"};
}
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;
}
char* argv[] = {
(char*)dat,
(char*)inputs,
(char*)output,
const_cast<char*>(dat),
const_cast<char*>(inputs),
const_cast<char*>(output),
nullptr
};
return main(3, argv);
const int code = main(3, argv);
if (code == 0) {
return status::ok();
}
return status::from_code(status::StatusCode::DynError);
}
// ---- Memory-based entry point ----
extern "C" int generate_witness(const WitnessInput input, Bytes* output) {
// TODO
return 0;
static status::Status validate_witness_input(const WitnessInput* input, const Bytes* output) {
if (output == nullptr) {
return status::Status{status::StatusCode::InvalidInput, "output is null"};
}
if (output->data != nullptr) {
return status::Status{status::StatusCode::InvalidInput, "output.data is not null"};
}
if (input == nullptr) {
return status::Status{status::StatusCode::InvalidInput, "input is null"};
}
if (input->dat.data == nullptr) {
return status::Status{status::StatusCode::InvalidInput, "input.dat.data is null"};
}
if (input->dat.size == 0) {
return status::Status{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::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;
}
// 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"};
}
std::copy(dummy_witness, dummy_witness + witness_size, witness_data);
output->data = witness_data;
output->size = witness_size;
return status::ok();
}

View File

@ -21,20 +21,30 @@ extern "C" {
///
/// - `dat`: Path to the .dat file. Must be extensionless.
/// - `inputs`: Path to the inputs file for the circuit. Must be a JSON file.
/// - `output`: Path where the output witness file will be written.
int generate_witness_from_files(const char* dat, const char* inputs, const char* output);
/// - `output`: Path to the output file where the witness will be written.
///
/// # Returns
///
/// 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);
/// Generates a witness from in-memory buffers.
///
/// # Parameters
///
/// - `input`: The `WitnessInput` struct containing the circuit information.
/// - `output`: On success, this will be populated with the generated witness bytes.
/// The caller is responsible for freeing this buffer.
int generate_witness(const WitnessInput input, Bytes* output);
/// - `output`: Pointer to a `Bytes` struct that will be populated with the generated witness bytes.
///
/// # 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 failure, returns a `Status` with an appropriate error code, and `output` will not be modified.
status::Status generate_witness(const WitnessInput* input, Bytes* output);
#ifdef __cplusplus
}
#endif
#endif // FFI_HPP
#endif

View File

@ -1,9 +1,8 @@
#ifndef TYPES_HPP
#define TYPES_HPP
#include <stddef.h>
#include <stdint.h>
#include <cassert>
#include <cstddef>
#include <cstdint>
/// A pointer to a contiguous sequence of elements with a known length.
///
@ -24,71 +23,35 @@ using Bytes = Slice<uint8_t>;
/// Immutable byte buffer.
using ConstBytes = Slice<const uint8_t>;
namespace result {
namespace status_code {
/// Represents the outcome of an operation.
enum StatusCode {
Ok = 0,
InvalidInput = 1,
};
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 code != Ok;
}
inline bool is_ok(const StatusCode code) {
return code == Ok;
}
using StatusCode = status_code::StatusCode;
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 = nullptr;
Status() : code(StatusCode::Ok) {}
explicit Status(const StatusCode code) : code(code) {}
Status(const StatusCode code, const char* message) : code(code), message(message) {}
bool is_ok() const { return status_code::is_ok(code); }
bool is_error() const { return status_code::is_error(code); }
const char* message;
};
/// A result type that encapsulates either a successful value of type `T` or an error status.
///
/// # Note
///
/// There's no distinction between the `Ok` and `Error` variants at the type level.
/// Instead, the `status` field indicates whether the result is successful or an error.
/// Consumers are responsible for checking the status before accessing the value.
template<typename T>
struct Result {
/// The result value. Undefined behavior if `is_error()`.
T value;
Status status;
inline Status from_code(const StatusCode code) { return Status { code, nullptr }; }
inline Status ok() { return from_code(Ok); }
static Result ok(T value) { return Result{value, Status{}}; }
/// Constructs an error result with a fallback value for non-default-constructible `T`.
static Result error(const T fallback, const Status status) {
assert(status.is_error() && "Result::error() called with Ok status.");
return Result{fallback, status};
}
/// Constructs an error result. Requires `T` to be default-constructible.
static Result error(const Status status) {
return Result::error(T{}, status);
}
/// Constructs an error result from a status code. Requires `T` to be default-constructible.
static Result error(const StatusCode status_code) {
const Status status{status_code};
return Result::error(status);
}
Result(T value, const Status status) : value(value), status(status) {}
inline bool is_ok(const Status status) { return is_ok(status.code); }
inline bool is_error(const Status status) { return is_error(status.code); }
bool is_ok() const { return status.is_ok(); }
bool is_error() const { return status.is_error(); }
};
}
#endif // TYPES_HPP