From 1b20438c630c637fd121aa7487b9f62e65c28d41 Mon Sep 17 00:00:00 2001 From: Balazs Komuves Date: Thu, 18 Jan 2024 13:04:26 +0100 Subject: [PATCH] initial draft of a CLI executable --- .gitignore | 1 + cli/cli_main.nim | 221 +++++++++++++++++++++++++++++++++++++++++++++++ cli/nim.cfg | 1 + groth16.nimble | 1 + 4 files changed, 224 insertions(+) create mode 100644 cli/cli_main.nim create mode 100644 cli/nim.cfg diff --git a/.gitignore b/.gitignore index 110e37e..f7b38cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store _bck* +build tmp main main.nim diff --git a/cli/cli_main.nim b/cli/cli_main.nim new file mode 100644 index 0000000..3a08375 --- /dev/null +++ b/cli/cli_main.nim @@ -0,0 +1,221 @@ + +import sugar +import std/strutils +import std/sequtils +import std/os +import std/parseopt +import std/[times,os] +import std/options +import strformat + +import groth16/prover +import groth16/verifier +import groth16/files/witness +import groth16/files/r1cs +import groth16/files/zkey +import groth16/files/export_json +import groth16/zkey_types +import groth16/fake_setup + +#------------------------------------------------------------------------------- + +proc printHelp() = + echo "usage:" + echo "$ nim-groth16 [options] --output=proof_input.json --circom=proof_main.circom" + echo "" + echo "available options:" + echo " -h, --help : print this help" + echo " -v, --verbose : verbose output" + echo " -t, --time : print time measurements" + echo " -p, --prove : create a proof" + echo " -y, --verify : verify a proof" + echo " -s, --setup : perform (fake) trusted setup" + echo " -z, --zkey = : the `.zkey` file" + echo " -w, --wtns = : the `.wtns` file" + echo " -r, --r1cs = : the `.r1cs` file" + echo " -o, --output = : the proof file" + echo " -i, --io = : the public input/output file" + +#------------------------------------------------------------------------------- + +type Config = object + zkey_file: string + r1cs_file: string + wtns_file: string + output_file: string + io_file: string + verbose: bool + measure_time: bool + do_prove: bool + do_verify: bool + do_setup: bool + +const dummyConfig = + Config( zkey_file: "" + , r1cs_file: "" + , wtns_file: "" + , output_file: "" + , io_file: "" + , verbose: false + , measure_time: false + , do_prove: false + , do_verify: false + , do_setup: false + ) + +proc printConfig(cfg: Config) = + echo "" + echo "zkey file = " & ($cfg.zkey_file) + echo "witness file = " & ($cfg.wtns_file) + echo "r1cs file = " & ($cfg.r1cs_file) + echo "proof file = " & ($cfg.output_file) + echo "public i/o file = " & ($cfg.io_file) + +#------------------------------------------------------------------------------- + +proc parseCliOptions(): Config = + + var argCtr: int = 0 + var swCtr: int = 0 + + var cfg: Config = dummyConfig + + for kind, key, value in getOpt(): + case kind + + # Positional arguments + of cmdArgument: + # echo ("arg #" & $argCtr & " = " & key) + argCtr += 1 + + # Switches + of cmdLongOption, cmdShortOption: + swCtr += 1 + case key + + of "h", "help" : printHelp() + of "v", "verbose" : cfg.verbose = true + of "t", "time" : cfg.measure_time = true + of "p", "prove" : cfg.do_prove = true + of "y", "verify" : cfg.do_verify = true + of "s", "setup" : cfg.do_setup = true + of "o", "output" : cfg.output_file = value + of "r", "r1cs" : cfg.r1cs_file = value + of "z", "zkey" : cfg.zkey_file = value + of "w", "wtns", "witness" : cfg.wtns_file = value + of "i", "io", "input" : cfg.io_file = value + else: + echo "Unknown option: ", key + echo "use --help to get a list of options" + quit() + + of cmdEnd: + discard + + if swCtr==0 and argCtr==0: + printHelp() + quit() + + return cfg + +#------------------------------------------------------------------------------- + +func seconds(x: float): string = fmt"{x:.4f} seconds" + +func quoted(s: string): string = fmt"`{s:s}`" + +#------------------------------------------------------------------------------- + +#[ +proc testProveAndVerify*( zkey_fname, wtns_fname: string): (VKey,Proof) = + + echo("parsing witness & zkey files...") + let witness = parseWitness( wtns_fname) + let zkey = parseZKey( zkey_fname) + + echo("generating proof...") + let start = cpuTime() + let proof = generateProof( zkey, witness ) + let elapsed = cpuTime() - start + echo("proving took ",seconds(elapsed)) + + echo("verifying the proof...") + let vkey = extractVKey( zkey) + let ok = verifyProof( vkey, proof ) + echo("verification succeeded = ",ok) + + return (vkey,proof) +]# + +#------------------------------------------------------------------------------- + +proc cliMain(cfg: Config) = + + var wtns: Witness + var zkey: ZKey + var r1cs: R1CS + var proof: Proof + + if not (cfg.wtns_file == ""): + echo("\nparsing witness file " & quoted(cfg.wtns_file)) + let start = cpuTime() + wtns = parseWitness(cfg.wtns_file) + let elapsed = cpuTime() - start + if cfg.measure_time: echo("parsing the witness took ",seconds(elapsed)) + + if not (cfg.zkey_file == ""): + echo("\nparsing zkey file " & quoted(cfg.zkey_file)) + let start = cpuTime() + zkey = parseZKey(cfg.zkey_file) + let elapsed = cpuTime() - start + if cfg.measure_time: echo("parsing the zkey took ",seconds(elapsed)) + + if not (cfg.r1cs_file == ""): + echo("\nparsing r1cs file " & quoted(cfg.r1cs_file)) + let start = cpuTime() + r1cs = parseR1CS(cfg.r1cs_file) + let elapsed = cpuTime() - start + if cfg.measure_time: echo("parsing the r1cs took ",seconds(elapsed)) + + if cfg.do_setup: + echo("\nerror:setup is not yet implemented") + quit() + + if cfg.do_prove: + if (cfg.wtns_file == "") or (cfg.zkey_file == ""): + echo("cannot prove: missing witness and/or zkey file!") + quit() + else: + echo("generating proof...") + let start = cpuTime() + proof = generateProof( zkey, wtns) + let elapsed = cpuTime() - start + if cfg.measure_time: echo("proving took ",seconds(elapsed)) + if not (cfg.output_file == ""): + echo("exporting the proof to " & quoted(cfg.output_file)) + exportProof( cfg.output_file, proof ) + if not (cfg.io_file == ""): + echo("exporting the public IO to " & quoted(cfg.io_file)) + exportPublicIO( cfg.io_file, proof ) + + if cfg.do_verify: + if (cfg.zkey_file == ""): + echo("cannot verify: missing vkey (well, zkey)") + quit() + else: + let vkey = extractVKey( zkey) + echo("\nverifying the proof...") + let start = cpuTime() + let ok = verifyProof( vkey, proof ) + let elapsed = cpuTime() - start + echo("verification succeeded = ",ok) + if cfg.measure_time: echo("verifying took ",seconds(elapsed)) + + echo("") + +#------------------------------------------------------------------------------- + +when isMainModule: + let cfg = parseCliOptions() + if cfg.verbose: printConfig(cfg) + cliMain(cfg) diff --git a/cli/nim.cfg b/cli/nim.cfg new file mode 100644 index 0000000..0f840a1 --- /dev/null +++ b/cli/nim.cfg @@ -0,0 +1 @@ +--path:".." diff --git a/groth16.nimble b/groth16.nimble index 0f23ddb..c21656d 100644 --- a/groth16.nimble +++ b/groth16.nimble @@ -5,5 +5,6 @@ license = "MIT OR Apache-2.0" skipDirs = @["groth16/example"] binDir = "build" +namedBin = {"cli/cli_main": "nim-groth16"}.toTable() requires "https://github.com/mratsim/constantine#5f7ba18f2ed351260015397c9eae079a6decaee1" \ No newline at end of file