diff --git a/src/ffi.cpp b/src/ffi.cpp index 014afcd..a25dc8a 100644 --- a/src/ffi.cpp +++ b/src/ffi.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include @@ -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(dat), + const_cast(inputs), + const_cast(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(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(); } diff --git a/src/ffi.hpp b/src/ffi.hpp index ec29ece..ccdf06b 100644 --- a/src/ffi.hpp +++ b/src/ffi.hpp @@ -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 diff --git a/src/types.hpp b/src/types.hpp index b1b9246..1ed888a 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -1,9 +1,8 @@ #ifndef TYPES_HPP #define TYPES_HPP -#include -#include -#include +#include +#include /// A pointer to a contiguous sequence of elements with a known length. /// @@ -24,71 +23,35 @@ using Bytes = Slice; /// Immutable byte buffer. using ConstBytes = Slice; -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 - 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