mirror of
https://github.com/logos-blockchain/logos-blockchain-circuits.git
synced 2026-07-01 14:39:28 +00:00
Add other circuits FFIs and smoke tests.
This commit is contained in:
parent
fdd1305c0c
commit
7a10f70eca
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ result
|
||||
*_cpp/
|
||||
*.r1cs
|
||||
**/input.json
|
||||
**/*-input.json
|
||||
|
||||
@ -20,7 +20,7 @@ static uint8_t* read_file(const char* path, size_t* out_size) {
|
||||
int main() {
|
||||
Status status = poq_generate_witness_from_files(
|
||||
"poq",
|
||||
"../input.json",
|
||||
"../poq-input.json",
|
||||
"witness.wtns"
|
||||
);
|
||||
|
||||
@ -33,7 +33,7 @@ int main() {
|
||||
|
||||
size_t dat_size, json_size;
|
||||
uint8_t* dat_data = read_file("poq.dat", &dat_size);
|
||||
uint8_t* json_data = read_file("../input.json", &json_size);
|
||||
uint8_t* json_data = read_file("../poq-input.json", &json_size);
|
||||
|
||||
WitnessInput input = {
|
||||
{dat_data, dat_size},
|
||||
|
||||
50
justfile
50
justfile
@ -30,5 +30,53 @@ test-poq: poq
|
||||
g++ -std=c++11 -O3 -I blend/poq_cpp blend/poq_cpp/test_ffi.cpp -L blend/poq_cpp -lwitness_poq -lgmp -o blend/poq_cpp/test_ffi
|
||||
cd blend/poq_cpp && ./test_ffi
|
||||
|
||||
# Build the PoL circuit and its C++ witness generator, equivalent to the CI build.
|
||||
pol:
|
||||
circom mantle/pol.circom --c --r1cs --no_asm --O2 --output mantle
|
||||
# circom-generated main() has no return on the success path; patch it before -O3 turns it into an infinite loop
|
||||
sed -i ':a;N;$!ba;s/\n}\n\n*$/\n return 0;\n}/' mantle/pol_cpp/main.cpp
|
||||
cp -r {{src}}/pol mantle/pol_cpp/pol
|
||||
cp {{src}}/circom_adapter.cpp {{src}}/circom_adapter.hpp {{src}}/circom_fwd.hpp {{src}}/types.hpp mantle/pol_cpp/
|
||||
cp {{ci_makefile}} mantle/pol_cpp/Makefile
|
||||
cp mantle/test_pol.cpp mantle/pol_cpp/test_pol.cpp
|
||||
make -C mantle/pol_cpp PROJECT=pol linux-lib
|
||||
|
||||
# Run a simple smoke test of the PoL witness generator.
|
||||
test-pol: pol
|
||||
g++ -std=c++11 -O3 -I mantle/pol_cpp mantle/pol_cpp/test_pol.cpp -L mantle/pol_cpp -lwitness_pol -lgmp -o mantle/pol_cpp/test_pol
|
||||
cd mantle/pol_cpp && ./test_pol
|
||||
|
||||
# Build the PoC circuit and its C++ witness generator, equivalent to the CI build.
|
||||
poc:
|
||||
circom mantle/poc.circom --c --r1cs --no_asm --O2 --output mantle
|
||||
# circom-generated main() has no return on the success path; patch it before -O3 turns it into an infinite loop
|
||||
sed -i ':a;N;$!ba;s/\n}\n\n*$/\n return 0;\n}/' mantle/poc_cpp/main.cpp
|
||||
cp -r {{src}}/poc mantle/poc_cpp/poc
|
||||
cp {{src}}/circom_adapter.cpp {{src}}/circom_adapter.hpp {{src}}/circom_fwd.hpp {{src}}/types.hpp mantle/poc_cpp/
|
||||
cp {{ci_makefile}} mantle/poc_cpp/Makefile
|
||||
cp mantle/test_poc.cpp mantle/poc_cpp/test_poc.cpp
|
||||
make -C mantle/poc_cpp PROJECT=poc linux-lib
|
||||
|
||||
# Run a simple smoke test of the PoC witness generator.
|
||||
test-poc: poc
|
||||
g++ -std=c++11 -O3 -I mantle/poc_cpp mantle/poc_cpp/test_poc.cpp -L mantle/poc_cpp -lwitness_poc -lgmp -o mantle/poc_cpp/test_poc
|
||||
cd mantle/poc_cpp && ./test_poc
|
||||
|
||||
# Build the signature circuit and its C++ witness generator, equivalent to the CI build.
|
||||
signature:
|
||||
circom mantle/signature.circom --c --r1cs --no_asm --O2 --output mantle
|
||||
# circom-generated main() has no return on the success path; patch it before -O3 turns it into an infinite loop
|
||||
sed -i ':a;N;$!ba;s/\n}\n\n*$/\n return 0;\n}/' mantle/signature_cpp/main.cpp
|
||||
cp -r {{src}}/signature mantle/signature_cpp/signature
|
||||
cp {{src}}/circom_adapter.cpp {{src}}/circom_adapter.hpp {{src}}/circom_fwd.hpp {{src}}/types.hpp mantle/signature_cpp/
|
||||
cp {{ci_makefile}} mantle/signature_cpp/Makefile
|
||||
cp mantle/test_signature.cpp mantle/signature_cpp/test_signature.cpp
|
||||
make -C mantle/signature_cpp PROJECT=signature linux-lib
|
||||
|
||||
# Run a simple smoke test of the signature witness generator.
|
||||
test-signature: signature
|
||||
g++ -std=c++11 -O3 -I mantle/signature_cpp mantle/signature_cpp/test_signature.cpp -L mantle/signature_cpp -lwitness_signature -lgmp -o mantle/signature_cpp/test_signature
|
||||
cd mantle/signature_cpp && ./test_signature
|
||||
|
||||
clean:
|
||||
rm -rf blend/poq_cpp
|
||||
rm -rf blend/poq_cpp mantle/pol_cpp mantle/poc_cpp mantle/signature_cpp
|
||||
|
||||
64
mantle/test_poc.cpp
Normal file
64
mantle/test_poc.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "poc/ffi.hpp"
|
||||
|
||||
static uint8_t* read_file(const char* path, size_t* out_size) {
|
||||
FILE* f = fopen(path, "rb");
|
||||
if (!f) return nullptr;
|
||||
fseek(f, 0, SEEK_END);
|
||||
*out_size = ftell(f);
|
||||
rewind(f);
|
||||
uint8_t* buf = (uint8_t*)malloc(*out_size + 1);
|
||||
fread(buf, 1, *out_size, f);
|
||||
buf[*out_size] = '\0';
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Status status = poc_generate_witness_from_files(
|
||||
"poc",
|
||||
"../poc-input.json",
|
||||
"witness.wtns"
|
||||
);
|
||||
|
||||
if (status_is_error(status)) {
|
||||
fprintf(stderr, "Error [%d]: %s\n", status.code, status.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("generate_witness_from_files: OK\n");
|
||||
|
||||
size_t dat_size, json_size;
|
||||
uint8_t* dat_data = read_file("poc.dat", &dat_size);
|
||||
uint8_t* json_data = read_file("../poc-input.json", &json_size);
|
||||
|
||||
WitnessInput input = {
|
||||
{dat_data, dat_size},
|
||||
(const char*)json_data
|
||||
};
|
||||
Bytes output = {nullptr, 0};
|
||||
|
||||
status = poc_generate_witness(&input, &output);
|
||||
|
||||
free(dat_data);
|
||||
free(json_data);
|
||||
|
||||
if (status_is_error(status)) {
|
||||
fprintf(stderr, "Error [%d]: %s\n", status.code, status.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t wtns_size;
|
||||
uint8_t* wtns_data = read_file("witness.wtns", &wtns_size);
|
||||
assert(wtns_data != nullptr);
|
||||
assert(output.size == wtns_size);
|
||||
assert(memcmp(output.data, wtns_data, output.size) == 0);
|
||||
free(wtns_data);
|
||||
|
||||
printf("generate_witness: OK (%zu bytes, matches witness.wtns)\n", output.size);
|
||||
free_bytes(&output);
|
||||
return 0;
|
||||
}
|
||||
64
mantle/test_pol.cpp
Normal file
64
mantle/test_pol.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "pol/ffi.hpp"
|
||||
|
||||
static uint8_t* read_file(const char* path, size_t* out_size) {
|
||||
FILE* f = fopen(path, "rb");
|
||||
if (!f) return nullptr;
|
||||
fseek(f, 0, SEEK_END);
|
||||
*out_size = ftell(f);
|
||||
rewind(f);
|
||||
uint8_t* buf = (uint8_t*)malloc(*out_size + 1);
|
||||
fread(buf, 1, *out_size, f);
|
||||
buf[*out_size] = '\0';
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Status status = pol_generate_witness_from_files(
|
||||
"pol",
|
||||
"../pol-input.json",
|
||||
"witness.wtns"
|
||||
);
|
||||
|
||||
if (status_is_error(status)) {
|
||||
fprintf(stderr, "Error [%d]: %s\n", status.code, status.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("generate_witness_from_files: OK\n");
|
||||
|
||||
size_t dat_size, json_size;
|
||||
uint8_t* dat_data = read_file("pol.dat", &dat_size);
|
||||
uint8_t* json_data = read_file("../pol-input.json", &json_size);
|
||||
|
||||
WitnessInput input = {
|
||||
{dat_data, dat_size},
|
||||
(const char*)json_data
|
||||
};
|
||||
Bytes output = {nullptr, 0};
|
||||
|
||||
status = pol_generate_witness(&input, &output);
|
||||
|
||||
free(dat_data);
|
||||
free(json_data);
|
||||
|
||||
if (status_is_error(status)) {
|
||||
fprintf(stderr, "Error [%d]: %s\n", status.code, status.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t wtns_size;
|
||||
uint8_t* wtns_data = read_file("witness.wtns", &wtns_size);
|
||||
assert(wtns_data != nullptr);
|
||||
assert(output.size == wtns_size);
|
||||
assert(memcmp(output.data, wtns_data, output.size) == 0);
|
||||
free(wtns_data);
|
||||
|
||||
printf("generate_witness: OK (%zu bytes, matches witness.wtns)\n", output.size);
|
||||
free_bytes(&output);
|
||||
return 0;
|
||||
}
|
||||
64
mantle/test_signature.cpp
Normal file
64
mantle/test_signature.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "signature/ffi.hpp"
|
||||
|
||||
static uint8_t* read_file(const char* path, size_t* out_size) {
|
||||
FILE* f = fopen(path, "rb");
|
||||
if (!f) return nullptr;
|
||||
fseek(f, 0, SEEK_END);
|
||||
*out_size = ftell(f);
|
||||
rewind(f);
|
||||
uint8_t* buf = (uint8_t*)malloc(*out_size + 1);
|
||||
fread(buf, 1, *out_size, f);
|
||||
buf[*out_size] = '\0';
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Status status = signature_generate_witness_from_files(
|
||||
"signature",
|
||||
"../signature-input.json",
|
||||
"witness.wtns"
|
||||
);
|
||||
|
||||
if (status_is_error(status)) {
|
||||
fprintf(stderr, "Error [%d]: %s\n", status.code, status.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("generate_witness_from_files: OK\n");
|
||||
|
||||
size_t dat_size, json_size;
|
||||
uint8_t* dat_data = read_file("signature.dat", &dat_size);
|
||||
uint8_t* json_data = read_file("../signature-input.json", &json_size);
|
||||
|
||||
WitnessInput input = {
|
||||
{dat_data, dat_size},
|
||||
(const char*)json_data
|
||||
};
|
||||
Bytes output = {nullptr, 0};
|
||||
|
||||
status = signature_generate_witness(&input, &output);
|
||||
|
||||
free(dat_data);
|
||||
free(json_data);
|
||||
|
||||
if (status_is_error(status)) {
|
||||
fprintf(stderr, "Error [%d]: %s\n", status.code, status.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t wtns_size;
|
||||
uint8_t* wtns_data = read_file("witness.wtns", &wtns_size);
|
||||
assert(wtns_data != nullptr);
|
||||
assert(output.size == wtns_size);
|
||||
assert(memcmp(output.data, wtns_data, output.size) == 0);
|
||||
free(wtns_data);
|
||||
|
||||
printf("generate_witness: OK (%zu bytes, matches witness.wtns)\n", output.size);
|
||||
free_bytes(&output);
|
||||
return 0;
|
||||
}
|
||||
119
src/poc/ffi.cpp
Normal file
119
src/poc/ffi.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include "poc/ffi.hpp"
|
||||
#include "circom_fwd.hpp"
|
||||
#include "circom_adapter.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../types.hpp"
|
||||
|
||||
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_new(StatusCode_DynError, e.what());
|
||||
} catch (...) {
|
||||
return status_new(StatusCode_DynError, "An unknown error occurred.");
|
||||
}
|
||||
}
|
||||
|
||||
static Status validate_generate_witness_from_files_arguments(const char* dat, const char* inputs, const char* output) {
|
||||
if (dat == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "dat is null.");
|
||||
}
|
||||
if (inputs == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "inputs is null.");
|
||||
}
|
||||
if (output == nullptr) {
|
||||
return status_new(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*>(dat),
|
||||
const_cast<char*>(inputs),
|
||||
const_cast<char*>(output),
|
||||
nullptr
|
||||
};
|
||||
|
||||
const int code = circom_main(3, argv);
|
||||
if (code == 0) {
|
||||
return status_ok();
|
||||
}
|
||||
const std::string message = "Witness generation [circom main()] failed with code: " + std::to_string(code) + ".";
|
||||
return status_new(StatusCode_DynError, message.c_str());
|
||||
}
|
||||
|
||||
extern "C" Status poc_generate_witness_from_files(const char* dat, const char* inputs, const char* output) {
|
||||
const Status status = validate_generate_witness_from_files_arguments(dat, inputs, output); // NOLINT: if-init
|
||||
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 validate_witness_arguments(const WitnessInput* input, const Bytes* output) {
|
||||
if (input == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "input is null.");
|
||||
}
|
||||
if (input->dat.data == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "input.dat.data is null.");
|
||||
}
|
||||
if (input->dat.size == 0) {
|
||||
return status_new(StatusCode_InvalidInput, "input.dat.size is zero.");
|
||||
}
|
||||
if (input->inputs_json == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "input.inputs_json is null.");
|
||||
}
|
||||
|
||||
if (output == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "output is null.");
|
||||
}
|
||||
if (output->data != nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "output.data is not null.");
|
||||
}
|
||||
|
||||
return status_ok();
|
||||
}
|
||||
|
||||
static Status generate_witness_impl(const WitnessInput* input, Bytes* output) {
|
||||
const ConstBytes& circuit_bytes = input->dat;
|
||||
|
||||
Circom_Circuit* circuit = loadCircuit(circuit_bytes);
|
||||
Circom_CalcWit* ctx = new Circom_CalcWit(circuit);
|
||||
|
||||
loadJson(ctx, input->inputs_json);
|
||||
if (ctx->getRemaingInputsToBeSet()!=0) {
|
||||
const std::string message = "Not all inputs have been set. Only " + std::to_string(get_main_input_signal_no()-ctx->getRemaingInputsToBeSet()) + " out of " + std::to_string(get_main_input_signal_no()) + ".";
|
||||
delete ctx;
|
||||
delete circuit;
|
||||
return status_new(StatusCode_InvalidInput, message.c_str());
|
||||
}
|
||||
|
||||
writeBinWitness(ctx, output);
|
||||
delete ctx;
|
||||
delete circuit;
|
||||
|
||||
return status_ok();
|
||||
}
|
||||
|
||||
extern "C" Status poc_generate_witness(const WitnessInput* input, Bytes* output) {
|
||||
const Status status = validate_witness_arguments(input, output); // NOLINT: if-init
|
||||
if (status_is_error(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return exceptions_into_status([&] {
|
||||
return generate_witness_impl(input, output);
|
||||
});
|
||||
}
|
||||
42
src/poc/ffi.hpp
Normal file
42
src/poc/ffi.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef FFI_POC_HPP
|
||||
#define FFI_POC_HPP
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Generates a witness by delegating to the circom-generated CLI entry point.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `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 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 poc_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`: 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 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 poc_generate_witness(const WitnessInput* input, Bytes* output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
119
src/pol/ffi.cpp
Normal file
119
src/pol/ffi.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include "pol/ffi.hpp"
|
||||
#include "circom_fwd.hpp"
|
||||
#include "circom_adapter.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../types.hpp"
|
||||
|
||||
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_new(StatusCode_DynError, e.what());
|
||||
} catch (...) {
|
||||
return status_new(StatusCode_DynError, "An unknown error occurred.");
|
||||
}
|
||||
}
|
||||
|
||||
static Status validate_generate_witness_from_files_arguments(const char* dat, const char* inputs, const char* output) {
|
||||
if (dat == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "dat is null.");
|
||||
}
|
||||
if (inputs == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "inputs is null.");
|
||||
}
|
||||
if (output == nullptr) {
|
||||
return status_new(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*>(dat),
|
||||
const_cast<char*>(inputs),
|
||||
const_cast<char*>(output),
|
||||
nullptr
|
||||
};
|
||||
|
||||
const int code = circom_main(3, argv);
|
||||
if (code == 0) {
|
||||
return status_ok();
|
||||
}
|
||||
const std::string message = "Witness generation [circom main()] failed with code: " + std::to_string(code) + ".";
|
||||
return status_new(StatusCode_DynError, message.c_str());
|
||||
}
|
||||
|
||||
extern "C" Status pol_generate_witness_from_files(const char* dat, const char* inputs, const char* output) {
|
||||
const Status status = validate_generate_witness_from_files_arguments(dat, inputs, output); // NOLINT: if-init
|
||||
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 validate_witness_arguments(const WitnessInput* input, const Bytes* output) {
|
||||
if (input == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "input is null.");
|
||||
}
|
||||
if (input->dat.data == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "input.dat.data is null.");
|
||||
}
|
||||
if (input->dat.size == 0) {
|
||||
return status_new(StatusCode_InvalidInput, "input.dat.size is zero.");
|
||||
}
|
||||
if (input->inputs_json == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "input.inputs_json is null.");
|
||||
}
|
||||
|
||||
if (output == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "output is null.");
|
||||
}
|
||||
if (output->data != nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "output.data is not null.");
|
||||
}
|
||||
|
||||
return status_ok();
|
||||
}
|
||||
|
||||
static Status generate_witness_impl(const WitnessInput* input, Bytes* output) {
|
||||
const ConstBytes& circuit_bytes = input->dat;
|
||||
|
||||
Circom_Circuit* circuit = loadCircuit(circuit_bytes);
|
||||
Circom_CalcWit* ctx = new Circom_CalcWit(circuit);
|
||||
|
||||
loadJson(ctx, input->inputs_json);
|
||||
if (ctx->getRemaingInputsToBeSet()!=0) {
|
||||
const std::string message = "Not all inputs have been set. Only " + std::to_string(get_main_input_signal_no()-ctx->getRemaingInputsToBeSet()) + " out of " + std::to_string(get_main_input_signal_no()) + ".";
|
||||
delete ctx;
|
||||
delete circuit;
|
||||
return status_new(StatusCode_InvalidInput, message.c_str());
|
||||
}
|
||||
|
||||
writeBinWitness(ctx, output);
|
||||
delete ctx;
|
||||
delete circuit;
|
||||
|
||||
return status_ok();
|
||||
}
|
||||
|
||||
extern "C" Status pol_generate_witness(const WitnessInput* input, Bytes* output) {
|
||||
const Status status = validate_witness_arguments(input, output); // NOLINT: if-init
|
||||
if (status_is_error(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return exceptions_into_status([&] {
|
||||
return generate_witness_impl(input, output);
|
||||
});
|
||||
}
|
||||
42
src/pol/ffi.hpp
Normal file
42
src/pol/ffi.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef FFI_POL_HPP
|
||||
#define FFI_POL_HPP
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Generates a witness by delegating to the circom-generated CLI entry point.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `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 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 pol_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`: 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 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 pol_generate_witness(const WitnessInput* input, Bytes* output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
119
src/signature/ffi.cpp
Normal file
119
src/signature/ffi.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include "signature/ffi.hpp"
|
||||
#include "circom_fwd.hpp"
|
||||
#include "circom_adapter.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../types.hpp"
|
||||
|
||||
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_new(StatusCode_DynError, e.what());
|
||||
} catch (...) {
|
||||
return status_new(StatusCode_DynError, "An unknown error occurred.");
|
||||
}
|
||||
}
|
||||
|
||||
static Status validate_generate_witness_from_files_arguments(const char* dat, const char* inputs, const char* output) {
|
||||
if (dat == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "dat is null.");
|
||||
}
|
||||
if (inputs == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "inputs is null.");
|
||||
}
|
||||
if (output == nullptr) {
|
||||
return status_new(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*>(dat),
|
||||
const_cast<char*>(inputs),
|
||||
const_cast<char*>(output),
|
||||
nullptr
|
||||
};
|
||||
|
||||
const int code = circom_main(3, argv);
|
||||
if (code == 0) {
|
||||
return status_ok();
|
||||
}
|
||||
const std::string message = "Witness generation [circom main()] failed with code: " + std::to_string(code) + ".";
|
||||
return status_new(StatusCode_DynError, message.c_str());
|
||||
}
|
||||
|
||||
extern "C" Status signature_generate_witness_from_files(const char* dat, const char* inputs, const char* output) {
|
||||
const Status status = validate_generate_witness_from_files_arguments(dat, inputs, output); // NOLINT: if-init
|
||||
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 validate_witness_arguments(const WitnessInput* input, const Bytes* output) {
|
||||
if (input == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "input is null.");
|
||||
}
|
||||
if (input->dat.data == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "input.dat.data is null.");
|
||||
}
|
||||
if (input->dat.size == 0) {
|
||||
return status_new(StatusCode_InvalidInput, "input.dat.size is zero.");
|
||||
}
|
||||
if (input->inputs_json == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "input.inputs_json is null.");
|
||||
}
|
||||
|
||||
if (output == nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "output is null.");
|
||||
}
|
||||
if (output->data != nullptr) {
|
||||
return status_new(StatusCode_InvalidInput, "output.data is not null.");
|
||||
}
|
||||
|
||||
return status_ok();
|
||||
}
|
||||
|
||||
static Status generate_witness_impl(const WitnessInput* input, Bytes* output) {
|
||||
const ConstBytes& circuit_bytes = input->dat;
|
||||
|
||||
Circom_Circuit* circuit = loadCircuit(circuit_bytes);
|
||||
Circom_CalcWit* ctx = new Circom_CalcWit(circuit);
|
||||
|
||||
loadJson(ctx, input->inputs_json);
|
||||
if (ctx->getRemaingInputsToBeSet()!=0) {
|
||||
const std::string message = "Not all inputs have been set. Only " + std::to_string(get_main_input_signal_no()-ctx->getRemaingInputsToBeSet()) + " out of " + std::to_string(get_main_input_signal_no()) + ".";
|
||||
delete ctx;
|
||||
delete circuit;
|
||||
return status_new(StatusCode_InvalidInput, message.c_str());
|
||||
}
|
||||
|
||||
writeBinWitness(ctx, output);
|
||||
delete ctx;
|
||||
delete circuit;
|
||||
|
||||
return status_ok();
|
||||
}
|
||||
|
||||
extern "C" Status signature_generate_witness(const WitnessInput* input, Bytes* output) {
|
||||
const Status status = validate_witness_arguments(input, output); // NOLINT: if-init
|
||||
if (status_is_error(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return exceptions_into_status([&] {
|
||||
return generate_witness_impl(input, output);
|
||||
});
|
||||
}
|
||||
42
src/signature/ffi.hpp
Normal file
42
src/signature/ffi.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef FFI_SIGNATURE_HPP
|
||||
#define FFI_SIGNATURE_HPP
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Generates a witness by delegating to the circom-generated CLI entry point.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `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 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 signature_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`: 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 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 signature_generate_witness(const WitnessInput* input, Bytes* output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user