From 35253db96b21aff967f494b8cd1c00e6acd496fe Mon Sep 17 00:00:00 2001 From: Dmitriy Ryajov Date: Fri, 19 Jan 2024 14:29:03 -0600 Subject: [PATCH] innitial commit --- .gitignore | 6 +++ .gitmodules | 3 ++ build.nims | 8 ++++ cbindgen.toml | 32 +++++++++++++++ circomcompat.nim | 22 +++++++++++ circomcompat.nimble | 14 +++++++ circomcompatffi.nim | 84 ++++++++++++++++++++++++++++++++++++++++ tests/config.nims | 1 + tests/testcircom.nim | 32 +++++++++++++++ vendor/circom-compat-ffi | 1 + 10 files changed, 203 insertions(+) create mode 100644 .gitmodules create mode 100644 build.nims create mode 100644 cbindgen.toml create mode 100644 circomcompat.nim create mode 100644 circomcompat.nimble create mode 100644 circomcompatffi.nim create mode 100644 tests/config.nims create mode 100644 tests/testcircom.nim create mode 160000 vendor/circom-compat-ffi diff --git a/.gitignore b/.gitignore index 32e1dc0..abd582a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ nimcache/ nimblecache/ htmldocs/ +* +!*/ +!*.* +*.exe + +.DS_Store diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..75cbe98 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/circom-compat-ffi"] + path = vendor/circom-compat-ffi + url = https://github.com/codex-storage/circom-compat-ffi.git diff --git a/build.nims b/build.nims new file mode 100644 index 0000000..c5924a3 --- /dev/null +++ b/build.nims @@ -0,0 +1,8 @@ +import std/os + +task genffi, "update the nim ffi bindings": + exec "cargo install --git https://github.com/arnetheduck/nbindgen#e80a85f1505d78eeae78ce33b6f406603be27d35 nbindgen" + exec "nbindgen -c ./cbindgen.toml vendor/circom-compat-ffi --output circomcompatffi.nim" + +task tests, "run unit tests": + exec "nim c -r tests/testcircomcompat.nim" diff --git a/cbindgen.toml b/cbindgen.toml new file mode 100644 index 0000000..4a8e115 --- /dev/null +++ b/cbindgen.toml @@ -0,0 +1,32 @@ +[parse] +parse_deps = false +expand = ["circom-compat-ffi"] + +# Configuration for name mangling +[export.mangle] +# Whether the types should be renamed during mangling, for example +# c_char -> CChar, etc. +rename_types = "CamelCase" +# Whether the underscores from the mangled name should be omitted. +remove_underscores = true + +[struct] +# A rule to use to rename struct field names. The renaming assumes the input is +# the Rust standard snake_case, however it acccepts all the different rename_args +# inputs. This means many options here are no-ops or redundant. +# +# possible values (that actually do something): +# * "CamelCase": my_arg => myArg +# * "PascalCase": my_arg => MyArg +# * "GeckoCase": my_arg => mMyArg +# * "ScreamingSnakeCase": my_arg => MY_ARG +# * "None": apply no renaming +# +# technically possible values (that shouldn't have a purpose here): +# * "SnakeCase": apply no renaming +# * "LowerCase": apply no renaming (actually applies to_lowercase, is this bug?) +# * "UpperCase": same as ScreamingSnakeCase in this context +# * "QualifiedScreamingSnakeCase" => same as ScreamingSnakeCase in this context +# +# default: "None" +rename_fields = "CamelCase" diff --git a/circomcompat.nim b/circomcompat.nim new file mode 100644 index 0000000..c6d3527 --- /dev/null +++ b/circomcompat.nim @@ -0,0 +1,22 @@ + +import std/os +import std/strutils +import std/macros + +const + currentDir = currentSourcePath().parentDir() + libDir* = currentDir/"vendor/circom-compat-ffi/target"/"release" + libPath* = libDir/"libcircom_compat_ffi.a" + +static: + let cmd = "cd vendor/circom-compat-ffi && cargo build --release" + warning "\nBuilding circom compat ffi: " & cmd + let (output, exitCode) = gorgeEx cmd + for ln in output.splitLines(): + warning("cargo> " & ln) + if exitCode != 0: + raiseAssert("Failed to build circom-compat-ffi") + +{.passl: "-lcircom_compat_ffi" & " -L" & libDir.} + +include circomcompatffi diff --git a/circomcompat.nimble b/circomcompat.nimble new file mode 100644 index 0000000..bebacec --- /dev/null +++ b/circomcompat.nimble @@ -0,0 +1,14 @@ +# Package + +version = "0.1.0" +author = "Dmitriy Ryajov" +description = "Nim wrapper for rust circom compat (ark-circom)" +license = "MIT" +srcDir = "src" + + +# Dependencies + +requires "nim >= 1.6.18" + +include "build.nims" \ No newline at end of file diff --git a/circomcompatffi.nim b/circomcompatffi.nim new file mode 100644 index 0000000..a4dd435 --- /dev/null +++ b/circomcompatffi.nim @@ -0,0 +1,84 @@ +const ERR_UNKNOWN* = -1 + +const ERR_OK* = 0 + +const ERR_WASM_PATH* = 1 + +const ERR_R1CS_PATH* = 2 + +const ERR_ZKEY_PATH* = 3 + +const ERR_INPUT_NAME* = 4 + +const ERR_INVALID_INPUT* = 5 + +const ERR_CANT_READ_ZKEY* = 6 + +const ERR_CIRCOM_BUILDER* = 7 + +const ERR_FAILED_TO_DESERIALIZE_PROOF* = 8 + +const ERR_FAILED_TO_DESERIALIZE_INPUTS* = 9 + + +type CircomCompatCtx* {.incompleteStruct.} = object + +type Buffer* = object + data*: pointer + len*: uint + +## # Safety +# +proc init_circom_compat*(r1cs_path: pointer, + wasm_path: pointer, + zkey_path: pointer, + ctx_ptr: ptr ptr CircomCompatCtx): int32 {.importc: "init_circom_compat".} + +proc release_circom_compat*(ctx_ptr: ptr ptr CircomCompatCtx): void {.importc: "release_circom_compat".} + +## # Safety +# +proc push_input_u256_array*(ctx_ptr: ptr CircomCompatCtx, + name_ptr: pointer, + input_ptr: pointer, + len: uint): int32 {.importc: "push_input_u256_array".} + +## # Safety +# +proc prove_circuit*(ctx_ptr: ptr CircomCompatCtx, + proof_bytes_ptr: ptr ptr Buffer, + inputs_bytes_ptr: ptr ptr Buffer): int32 {.importc: "prove_circuit".} + +## # Safety +# +proc verify_circuit*(ctx_ptr: ptr CircomCompatCtx, + proof_bytes_ptr: ptr Buffer, + inputs_bytes_ptr: ptr Buffer): int32 {.importc: "verify_circuit".} + +proc push_input_numeric_i8*(ctx_ptr: ptr CircomCompatCtx, + name_ptr: pointer, + input: int8): int32 {.importc: "push_input_numeric_i8".} + +proc push_input_numeric_u8*(ctx_ptr: ptr CircomCompatCtx, + name_ptr: pointer, + input: uint8): int32 {.importc: "push_input_numeric_u8".} + +proc push_input_numeric_i16*(ctx_ptr: ptr CircomCompatCtx, + name_ptr: pointer, + input: int16): int32 {.importc: "push_input_numeric_i16".} + +proc push_input_numeric_u16*(ctx_ptr: ptr CircomCompatCtx, + name_ptr: pointer, + input: uint16): int32 {.importc: "push_input_numeric_u16".} + +proc push_input_numeric_i32*(ctx_ptr: ptr CircomCompatCtx, + name_ptr: pointer, + input: int32): int32 {.importc: "push_input_numeric_i32".} + +proc push_input_numeric_u32*(ctx_ptr: ptr CircomCompatCtx, + name_ptr: pointer, + input: uint32): int32 {.importc: "push_input_numeric_u32".} + +proc push_input_numeric_u64*(ctx_ptr: ptr CircomCompatCtx, + name_ptr: pointer, + input: uint64): int32 {.importc: "push_input_numeric_u64".} diff --git a/tests/config.nims b/tests/config.nims new file mode 100644 index 0000000..b44aa35 --- /dev/null +++ b/tests/config.nims @@ -0,0 +1 @@ +switch("path", "$projectDir/") \ No newline at end of file diff --git a/tests/testcircom.nim b/tests/testcircom.nim new file mode 100644 index 0000000..1542bd5 --- /dev/null +++ b/tests/testcircom.nim @@ -0,0 +1,32 @@ +import std/os +import std/unittest + +import ../circomcompat + +suite "Test circom compat nim": + test "Should generate witness, prove and verify": + let + r1csPath = "vendor/circom-compat-ffi/fixtures/mycircuit.r1cs".cstring + wasmPath = "vendor/circom-compat-ffi/fixtures/mycircuit.wasm".cstring + + var ctx: ptr CircomCompatCtx + let res = init_circom_compat( + r1csPath, + wasmPath, + nil, + ctx.addr) + + check ctx.push_input_numeric_i8("a".cstring, 3) == ERR_OK + check ctx.push_input_numeric_i8("b".cstring, 11) == ERR_OK + + var proofBytes: ptr Buffer + var publicBytes: ptr Buffer + + check ctx.prove_circuit(proofBytes.addr, publicBytes.addr) == ERR_OK + + check proofBytes.len > 0 + check publicBytes.len > 0 + + check ctx.verify_circuit(proofBytes, publicBytes) == ERR_OK + + check res == ERR_OK diff --git a/vendor/circom-compat-ffi b/vendor/circom-compat-ffi new file mode 160000 index 0000000..5a52223 --- /dev/null +++ b/vendor/circom-compat-ffi @@ -0,0 +1 @@ +Subproject commit 5a522239a62262f6b0fefa1f1d54a22b72da5b38