diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 826a7cc..a472884 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -264,7 +264,7 @@ jobs: make ios make ios_simulator make macos_arm64 - ctest --rerun-failed --output-on-failure + cd build_prover_macos_arm64 && ctest --rerun-failed --output-on-failure - name: test rapidsnark run: | diff --git a/.gitignore b/.gitignore index 179392b..e084d7b 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,4 @@ build/fq_asm.o build/fr_asm.o .idea/ +.vscode/ diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 1139dc9..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "proofServer", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/build/proverServer", - "args": ["/home/jordi/circuits/tools/rollup-376-32-256-64/circuit-376-32-256-64.dat", "/home/jordi/circuits/tools/rollup-376-32-256-64/circuit-376-32-256-64_0001.zkey" ], - "stopAtEntry": false, - "cwd": "${workspaceFolder}/build", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ea578ea..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "files.associations": { - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "bitset": "cpp", - "cctype": "cpp", - "chrono": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "condition_variable": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "forward_list": "cpp", - "list": "cpp", - "map": "cpp", - "unordered_map": "cpp", - "unordered_set": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "buffer": "cpp", - "executor": "cpp", - "functional": "cpp", - "internet": "cpp", - "io_context": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "netfwd": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "ratio": "cpp", - "regex": "cpp", - "socket": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "timer": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "fstream": "cpp", - "future": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "mutex": "cpp", - "new": "cpp", - "ostream": "cpp", - "shared_mutex": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "thread": "cpp", - "cinttypes": "cpp", - "typeinfo": "cpp", - "csignal": "cpp", - "set": "cpp", - "valarray": "cpp", - "variant": "cpp" - } -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index c793486..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "buildProverServer", - "type": "shell", - "command": "npx task buildProverServer /home/jordi/circuits/tools/rollup-376-32-256-64/circuit-376-32-256-64.cpp", - "group": { - "kind": "build", - "isDefault": true - }, - "presentation": { - "reveal": "always", - "panel": "new" - }, - "problemMatcher": { - "owner": "cpp", - "fileLocation": [ - "relative", - "${workspaceFolder}/build" - ], - "pattern": [ - { - "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", - "file": 1, - "line": 2, - "column": 3, - "severity": 4, - "message": 5 - } - ] - } - }, - { - "label": "buildProver", - "type": "shell", - "command": "npx task buildProver", - "group": { - "kind": "build", - "isDefault": true - }, - "presentation": { - "reveal": "always", - "panel": "new" - }, - "problemMatcher": { - "owner": "cpp", - "fileLocation": [ - "relative", - "${workspaceFolder}/build" - ], - "pattern": [ - { - "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", - "file": 1, - "line": 2, - "column": 3, - "severity": 4, - "message": 5 - } - ] - } - }, - ] -} \ No newline at end of file diff --git a/src/prover.cpp b/src/prover.cpp index 60b868d..8221cd6 100644 --- a/src/prover.cpp +++ b/src/prover.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -14,13 +15,6 @@ using json = nlohmann::json; -class ShortBufferException : public std::invalid_argument -{ -public: - explicit ShortBufferException(const std::string &msg) - : std::invalid_argument(msg) {} -}; - class InvalidWitnessLengthException : public std::invalid_argument { public: @@ -31,23 +25,33 @@ class InvalidWitnessLengthException : public std::invalid_argument static void CopyError( char *error_msg, - unsigned long long error_msg_maxsize, + size_t error_msg_maxsize, const std::exception &e) { - if (error_msg) { - strncpy(error_msg, e.what(), error_msg_maxsize); - } + if (!error_msg || error_msg_maxsize == 0) return; + std::snprintf(error_msg, error_msg_maxsize, "%s", e.what()); } static void -CopyError( +CopyErrorFmt( + char *error_msg, + unsigned long long error_msg_maxsize, + const char *format, + ...) __attribute__((format(printf, 3, 4))); + +static void +CopyErrorFmt( char *error_msg, unsigned long long error_msg_maxsize, - const char *str) + const char *format, + ...) { - if (error_msg) { - strncpy(error_msg, str, error_msg_maxsize); - } + if (!error_msg || error_msg_maxsize == 0) return; + + va_list args; + va_start(args, format); + std::vsnprintf(error_msg, error_msg_maxsize, format, args); + va_end(args); } static unsigned long long @@ -90,33 +94,6 @@ BuildPublicString(AltBn128::FrElement *wtnsData, uint32_t nPublic) return jsonPublic.dump(); } -static void -CheckAndUpdateBufferSizes( - unsigned long long proofCalcSize, - unsigned long long *proofSize, - unsigned long long publicCalcSize, - unsigned long long *publicSize, - const std::string &type) -{ - if (*proofSize < proofCalcSize || *publicSize < publicCalcSize) { - - *proofSize = proofCalcSize; - *publicSize = publicCalcSize; - - if (*proofSize < proofCalcSize) { - throw ShortBufferException("Proof buffer is too short. " + type + " size: " - + std::to_string(proofCalcSize) + - ", actual size: " - + std::to_string(*proofSize)); - } else { - throw ShortBufferException("Public buffer is too short. " + type + " size: " - + std::to_string(proofCalcSize) + - ", actual size: " - + std::to_string(*proofSize)); - } - } -} - class Groth16Prover { BinFileUtils::BinFile zkey; @@ -179,16 +156,6 @@ class Groth16Prover stringProof = proof->toJson().dump(); stringPublic = BuildPublicString(wtnsData, zkeyHeader->nPublic); } - - unsigned long long proofBufferMinSize() const - { - return ProofBufferMinSize(); - } - - unsigned long long publicBufferMinSize() const - { - return PublicBufferMinSize(zkeyHeader->nPublic); - } }; int @@ -210,7 +177,7 @@ groth16_public_size_for_zkey_buf( return PROVER_ERROR; } catch (...) { - CopyError(error_msg, error_msg_maxsize, "unknown error"); + CopyErrorFmt(error_msg, error_msg_maxsize, "unknown error"); return PROVER_ERROR; } @@ -235,7 +202,7 @@ groth16_public_size_for_zkey_file( return PROVER_ERROR; } catch (...) { - CopyError(error_msg, error_msg_maxsize, "unknown error"); + CopyErrorFmt(error_msg, error_msg_maxsize, "unknown error"); return PROVER_ERROR; } @@ -280,7 +247,7 @@ groth16_prover_create( return PROVER_ERROR; } catch (...) { - CopyError(error_msg, error_msg_maxsize, "unknown error"); + CopyErrorFmt(error_msg, error_msg_maxsize, "unknown error"); return PROVER_ERROR; } @@ -324,60 +291,48 @@ groth16_prover_prove( char *error_msg, unsigned long long error_msg_maxsize) { - try { - if (prover_object == NULL) { - throw std::invalid_argument("Null prover object"); - } - - if (wtns_buffer == NULL) { - throw std::invalid_argument("Null witness buffer"); - } + if (!prover_object) { + CopyErrorFmt(error_msg, error_msg_maxsize, "Null prover object"); + return PROVER_ERROR; + } - if (proof_buffer == NULL) { - throw std::invalid_argument("Null proof buffer"); - } + if (!wtns_buffer) { + CopyErrorFmt(error_msg, error_msg_maxsize, "Null witness buffer"); + return PROVER_ERROR; + } - if (proof_size == NULL) { - throw std::invalid_argument("Null proof size"); - } + if (!proof_buffer) { + CopyErrorFmt(error_msg, error_msg_maxsize, "Null proof buffer"); + return PROVER_ERROR; + } - if (public_buffer == NULL) { - throw std::invalid_argument("Null public buffer"); - } + if (!proof_size) { + CopyErrorFmt(error_msg, error_msg_maxsize, "Null proof size"); + return PROVER_ERROR; + } - if (public_size == NULL) { - throw std::invalid_argument("Null public size"); - } + if (!public_buffer) { + CopyErrorFmt(error_msg, error_msg_maxsize, "Null public buffer"); + return PROVER_ERROR; + } - Groth16Prover *prover = static_cast(prover_object); + if (!public_size) { + CopyErrorFmt(error_msg, error_msg_maxsize, "Null public size"); + return PROVER_ERROR; + } - CheckAndUpdateBufferSizes(prover->proofBufferMinSize(), proof_size, - prover->publicBufferMinSize(), public_size, - "Minimum"); + auto prover = static_cast(prover_object); - std::string stringProof; - std::string stringPublic; + std::string stringProof; + std::string stringPublic; + try { prover->prove(wtns_buffer, wtns_size, stringProof, stringPublic); - CheckAndUpdateBufferSizes(stringProof.length(), proof_size, - stringPublic.length(), public_size, - "Required"); - - *proof_size = stringProof.length(); - *public_size = stringPublic.length(); - - std::strncpy(proof_buffer, stringProof.c_str(), *proof_size); - std::strncpy(public_buffer, stringPublic.c_str(), *public_size); - } catch(InvalidWitnessLengthException& e) { CopyError(error_msg, error_msg_maxsize, e); return PROVER_INVALID_WITNESS_LENGTH; - } catch(ShortBufferException& e) { - CopyError(error_msg, error_msg_maxsize, e); - return PROVER_ERROR_SHORT_BUFFER; - } catch (std::exception& e) { CopyError(error_msg, error_msg_maxsize, e); return PROVER_ERROR; @@ -388,10 +343,39 @@ groth16_prover_prove( return PROVER_ERROR; } catch (...) { - CopyError(error_msg, error_msg_maxsize, "unknown error"); + CopyErrorFmt(error_msg, error_msg_maxsize, "unknown error"); + return PROVER_ERROR; + } + + // Check for overflow before adding 1 for null terminator + if (stringProof.length() >= ULLONG_MAX || stringPublic.length() >= ULLONG_MAX) { + CopyErrorFmt(error_msg, error_msg_maxsize, "Proof or public data too large"); return PROVER_ERROR; } + unsigned long long requiredProofSize = stringProof.length() + 1; + unsigned long long requiredPublicSize = stringPublic.length() + 1; + + if (*proof_size < requiredProofSize || *public_size < requiredPublicSize) { + unsigned long long origProofSize = *proof_size; + unsigned long long origPublicSize = *public_size; + *proof_size = requiredProofSize; + *public_size = requiredPublicSize; + + CopyErrorFmt(error_msg, error_msg_maxsize, + "Buffer insufficient for generated proof. Required - proof: %llu (provided: %llu), public: %llu (provided: %llu)", + requiredProofSize, origProofSize, requiredPublicSize, origPublicSize); + return PROVER_ERROR_SHORT_BUFFER; + } + + std::memcpy(proof_buffer, stringProof.c_str(), stringProof.length()); + proof_buffer[stringProof.length()] = '\0'; + *proof_size = stringProof.length(); + + std::memcpy(public_buffer, stringPublic.c_str(), stringPublic.length()); + public_buffer[stringPublic.length()] = '\0'; + *public_size = stringPublic.length(); + return PROVER_OK; } diff --git a/src/prover.h b/src/prover.h index 8baaa12..4a525f7 100644 --- a/src/prover.h +++ b/src/prover.h @@ -5,7 +5,7 @@ extern "C" { #endif -//Error codes returned by the functions. +// Error codes returned by the functions. #define PROVER_OK 0x0 #define PROVER_ERROR 0x1 #define PROVER_ERROR_SHORT_BUFFER 0x2 @@ -50,7 +50,7 @@ groth16_proof_size( * Initializes 'prover_object' with a pointer to a new prover object. * @return error code: * PROVER_OK - in case of success - * PPOVER_ERROR - in case of an error + * PROVER_ERROR - in case of an error */ int groth16_prover_create( @@ -64,7 +64,7 @@ groth16_prover_create( * Initializes 'prover_object' with a pointer to a new prover object. * @return error code: * PROVER_OK - in case of success - * PPOVER_ERROR - in case of an error + * PROVER_ERROR - in case of an error */ int groth16_prover_create_zkey_file( @@ -75,10 +75,23 @@ groth16_prover_create_zkey_file( /** * Proves 'wtns_buffer' and saves results to 'proof_buffer' and 'public_buffer'. + * + * @param prover_object Prover object created by groth16_prover_create + * @param wtns_buffer Witness data buffer + * @param wtns_size Size of witness buffer + * @param proof_buffer Buffer for proof output (JSON string) + * @param proof_size [in/out] On input: buffer size. On output: bytes written (excluding null terminator) + * @param public_buffer Buffer for public signals output (JSON string) + * @param public_size [in/out] On input: buffer size. On output: bytes written (excluding null terminator) + * @param error_msg Buffer for error message + * @param error_msg_maxsize Size of error message buffer + * * @return error code: - * PROVER_OK - in case of success - * PPOVER_ERROR - in case of an error - * PROVER_ERROR_SHORT_BUFFER - in case of a short buffer error, also updates proof_size and public_size with actual proof and public sizes + * PROVER_OK - success, proof_size and public_size contain bytes written (excluding null terminator) + * PROVER_ERROR_SHORT_BUFFER - buffers too small for generated proof/public signals, + * proof_size and public_size are updated with required sizes + * PROVER_INVALID_WITNESS_LENGTH - witness length doesn't match circuit + * PROVER_ERROR - other error, see error_msg */ int groth16_prover_prove( @@ -102,8 +115,9 @@ groth16_prover_destroy(void *prover_object); * groth16_prover * @return error code: * PROVER_OK - in case of success - * PPOVER_ERROR - in case of an error - * PROVER_ERROR_SHORT_BUFFER - in case of a short buffer error, also updates proof_size and public_size with actual proof and public sizes + * PROVER_ERROR_SHORT_BUFFER - buffers too small, proof_size and public_size updated with required sizes + * PROVER_INVALID_WITNESS_LENGTH - witness length doesn't match circuit + * PROVER_ERROR - other error, see error_msg */ int groth16_prover( @@ -122,8 +136,9 @@ groth16_prover( * groth16_prover_zkey_file * @return error code: * PROVER_OK - in case of success - * PPOVER_ERROR - in case of an error - * PROVER_ERROR_SHORT_BUFFER - in case of a short buffer error, also updates proof_size and public_size with actual proof and public sizes + * PROVER_ERROR_SHORT_BUFFER - buffers too small, proof_size and public_size updated with required sizes + * PROVER_INVALID_WITNESS_LENGTH - witness length doesn't match circuit + * PROVER_ERROR - other error, see error_msg */ int groth16_prover_zkey_file( diff --git a/src/test_public_size.c b/src/test_public_size.c index 73b7f19..420fa06 100644 --- a/src/test_public_size.c +++ b/src/test_public_size.c @@ -21,7 +21,7 @@ int test_groth16_public_size(const char *zkey_fname, unsigned long long *public_size) { int ret_val = 0; - const int error_sz = 256; + enum { error_sz = 256 }; char error_msg[error_sz]; int fd = open(zkey_fname, O_RDONLY); @@ -73,7 +73,7 @@ test_groth16_public_size(const char *zkey_fname, unsigned long long *public_size int test_groth16_public_size_for_zkey_file(const char *zkey_fname, unsigned long long *public_size) { - const int err_ln = 256; + enum { err_ln = 256 }; char error_msg[err_ln]; int ret = groth16_public_size_for_zkey_file(zkey_fname, public_size, error_msg, err_ln);