diff --git a/About_EZKL/Commands.md b/About_EZKL/Commands.md index 16139c8..8a1270d 100644 --- a/About_EZKL/Commands.md +++ b/About_EZKL/Commands.md @@ -8,15 +8,15 @@ Here is some more detail on `ezkl` commands. ### Getting an SRS -`ezkl` uses KZG commitments, which in turn require a structured reference string (SRS). You can download a [KZG](https://cypherpunks.ca/~iang/pubs/PolyCommit-AsiaCrypt.pdf) structured reference string with (for example) 17 rows as follows. +`ezkl` uses KZG commitments, which in turn require a structured reference string (SRS). You can download a [KZG](https://cypherpunks.ca/~iang/pubs/PolyCommit-AsiaCrypt.pdf) structured reference string with (for example) 17 rows as follows. This step is optional since under the hood, `ezkl` will automatically download an SRS and cache it in your file system if you don't have one when running the commands that require it. ```bash ezkl get-srs --logrows=17 --srs-path=17.srs ``` -This sets up a SRS that the prover can use to commit and the verifier can use to evaluate in a file called `17.srs`. +> **Note:** For all of the CLI commands, there will be defaults paths for all the artifacts that are generated and used. To keep things succinet, the rest of the demonstrated here will use the default paths. You can always append each ezkl command with `--help` to view all the args and a description of each one. -> **Note:** `ezkl` has a command `gen-srs` to generate an SRS for testing purposes when bandwidth is scarce. The SRS generated by `gen-srs` is not meant to be used in production. +This sets up a SRS that the prover can use to commit and the verifier can use to evaluate in a file called `17.srs`. > **Note:** Downsizing an SRS is time consuming, so if you obtain a logrows=20 SRS and the circuit uses logrows=17, the prove command will spend most of its time downsizing your 20.srs from 20 to 17. Once you know the logrows you need, use a file of that size for max speed. @@ -26,31 +26,27 @@ For `ezkl` to compute a snark, it needs some settings to determine how to create For example, this is the file generated from our CLI tutorial example: ```bash -ezkl gen-settings -M examples/onnx/4l_relu_conv_fc/network.onnx +cd examples/onnx/4l_relu_conv_fc/network.onnx +ezkl gen-settings ``` By default the settings file will be called `settings.json`. **`settings.json`:** ```javascript -{"run_args":{ - "tolerance":{"val":0.0,"scales":[1,1]},"scale":7,"bits":16,"logrows":17,"batch_size":1, - "input_visibility":"Private","output_visibility":"Public","param_visibility":"Private","allocated_constraints":null}, - "num_constraints":13172,"model_instance_shapes":[[1,10]],"model_output_scales":[14],"module_sizes":{"poseidon":[0,[0]],"elgamal":[0,[0,0,0]]}, - "required_lookups":[{"ReLU":{"scale":128}}], - "check_mode":"SAFE" - } +{"run_args":{"tolerance":{"val":0.0,"scale":1.0},"input_scale":7,"param_scale":7,"scale_rebase_multiplier":1,"lookup_range":[-32768,32768],"logrows":17,"num_inner_cols":2,"variables":[["batch_size",1]],"input_visibility":"Private","output_visibility":"Public","param_visibility":"Private","div_rebasing":false,"rebase_frac_zero_constants":false,"check_mode":"UNSAFE"},"num_rows":8617,"total_assignments":17235,"total_const_size":974,"total_dynamic_col_size":0,"num_dynamic_lookups":0,"num_shuffles":0,"total_shuffle_col_size":0,"model_instance_shapes":[[1,10]],"model_output_scales":[7],"model_input_scales":[7],"module_sizes":{"kzg":[],"poseidon":[0,[0]]},"required_lookups":["ReLU"],"required_range_checks":[[-64,64]],"check_mode":"UNSAFE","version":"0.0.0","num_blinding_factors":null,"timestamp":1710371522521} ``` Let's say our circuit was much larger; we need to bump `"logrows"` to 23. We can add a flag to our original command to specifiy this (using `-O` to give the output a different name): ```bash -ezkl gen-settings -M examples/onnx/4l_relu_conv_fc/network.onnx -O circuitK23.json --logrows 23 +ezkl gen-settings -O circuitK23.json --logrows 23 ``` This produces **`circuitK23.json`:** which is the same as the `settings.json` above, but with `"logrows"` now 23. You can do this for any other parameter for custom circuits. The `.json` file can also be manually edited to tweak the choices. + ### Calibrate Settings -There are a lot of adjustable knobs (such as bits, scale, and logrows) in `ezkl` that let you trade off between prover and verifier resources, accuracy, and control other parts of the zkp setup. While you are free to choose these manually with cli parameters passed to `gen-settings`, we recommend fine-tuning with the automatic calibration provided by the `calibrate-settings` command. This modifies your `settings.json` file with a suggested choice of circuit parameters: +There are a lot of adjustable knobs (such as lookup_range, scale, and logrows) in `ezkl` that let you trade off between prover and verifier resources, accuracy, and control other parts of the zkp setup. While you are free to choose these manually with cli parameters passed to `gen-settings`, we recommend fine-tuning with the automatic calibration provided by the `calibrate-settings` command. This modifies your `settings.json` file with a suggested choice of circuit parameters: ```bash -ezkl calibrate-settings -M examples/onnx/4l_relu_conv_fc/network.onnx -D examples/onnx/4l_relu_conv_fc/input.json --target resources +ezkl calibrate-settings -D input.json ``` You can also set the `--target` to **"accuracy"** if you want to optimize for numerical accuracy rather than CPU and memory performance. The default is set to **"resources"**. The largest tradeoff for these two is in the size of `"logrows"` and `"scale"`. With a higher scale, floating point numbers are interpreted more accurately. With a smaller logrows, a smaller, less memory-intensive circuit is generated. @@ -59,19 +55,16 @@ For example, after running the same command with `--target` set to **accuracy**, **settings.json**: ```javascript -{"run_args":{"tolerance":{"val":0.0,"scales":[1,1]},"scale":11,"bits":21,"logrows":22,"batch_size":1,"input_visibility":"Private","output_visibility":"Public","param_visibility":"Private","allocated_constraints":null}, -"num_constraints":13172,"model_instance_shapes":[[1,10]],"model_output_scales":[22],"module_sizes":{"poseidon":[0,[0]],"elgamal":[0,[0,0,0]]}, -"required_lookups":[{"ReLU":{"scale":2048}}], -"check_mode":"SAFE"} +{"run_args":{"tolerance":{"val":0.0,"scale":1.0},"input_scale":13,"param_scale":13,"scale_rebase_multiplier":2,"lookup_range":[-19413982,19196974],"logrows":26,"num_inner_cols":2,"variables":[["batch_size",1]],"input_visibility":"Private","output_visibility":"Public","param_visibility":"Private","div_rebasing":false,"rebase_frac_zero_constants":false,"check_mode":"UNSAFE"},"num_rows":8040,"total_assignments":16081,"total_const_size":685,"total_dynamic_col_size":0,"num_dynamic_lookups":0,"num_shuffles":0,"total_shuffle_col_size":0,"model_instance_shapes":[[1,10]],"model_output_scales":[26],"model_input_scales":[13],"module_sizes":{"kzg":[],"poseidon":[0,[0]]},"required_lookups":["ReLU"],"required_range_checks":[[-4096,4096]],"check_mode":"UNSAFE","version":"0.0.0","num_blinding_factors":null,"timestamp":1710371522521} ``` -> Note: You can still use the generic RunArgs for `mock` and `gen-witness` (e.g. `ezkl mock --logrows=22 --bits=21` rather than `ezkl mock --settings-path circuit.json`). However, `--settings-path` takes priority. +> Note: To ensure the lookup table range is big enough to not go out of range, the data file you pass to `calibrate-settings` should be representative of the data you will be using in your application. In our example `mnist_classifier.ipynb` notebook we pass 8 sample inputs to our `calibrate-settings`. You may want to pass more or less depending on your application and the expected possible range of your inputs. ### Compile circuit This converts and freezes the onnx file to what ezkl will actually prove against, incorporating the settings, quantizing, etc. ```bash -ezkl compile-circuit -M network.onnx -S settings.json --compiled-circuit network.ezkl +ezkl compile-circuit ``` ### Setup @@ -81,16 +74,16 @@ Along with our SRS and circuit parameters, we need two other elements to generat Run this command to set up your proving and verifying keys: ```bash -ezkl setup -M network.ezkl --srs-path=17.srs +ezkl setup ``` You should now have files called `vk.key` and `pk.key` in the root of your project. You can also specify different paths for these outputs with `--vk-path=altvk.key --pk-path=altpk.key` ### Generate witness -Now we take the input data, quantize it, and run it through the quantized model, performing any hashing or encryption, to obtain the input and output that we will be proving. +Now we take the input data, quantize it, and run it through the quantized model, performing any hashing or encryption, to obtain the input and output that we will be proving. A witness in the context of Zero Knowledge Proofs is a computational trace that allows a proof to be generated. The `gen-witness` function doesn't record all the intermediate values of the trace (such as the activations of inner layers in a neural network), but does write the final outputs of your neural network or computation graph in a form that is usable in the prove command, and human readable. ```bash -ezkl gen-witness -M network.ezkl -D examples/onnx/4l_relu_conv_fc/input.json +ezkl gen-witness ``` The default output file is `witness.json`. @@ -103,66 +96,69 @@ In a typical zk application, the proof will be generated by or on behalf of the Here is the command for generating a proof from the cli: ```bash -ezkl prove -M network.ezkl --witness witness.json --pk-path=pk.key --proof-path=model.proof --srs-path=15.srs +ezkl prove ``` -This will create a proof file called `model.proof` that anyone can later use to verify your model was run correctly on the input. +This will create a proof file called `proof.json` that anyone can later use to verify your model was run correctly on the input. ### Verify -Verification can be done from the CLI, in WASM, or on a blockchain. Verification will require the commitment scheme parameters, the circuit parameters, the verifying key, and, of course, the proof. When verifying with a smart contract, however, the verifying key and circuit/commitment params are baked into the smart contract; this means only the public parameters will be passed as calldata along with the proof. The command for verifying from the CLI is: +Verification can be done from the CLI, in the browser (via WASM or ephemeral EVM verification), or on a blockchain. Verification will require the commitment scheme parameters, the circuit parameters, the verifying key, and, of course, the proof. When verifying with a smart contract, however, the verifying key and circuit/commitment params are baked into the smart contract; this means only the public parameters will be passed as calldata along with the proof. The command for verifying from the CLI is: ```bash -ezkl verify --proof-path=model.proof --settings-path=settings.json --vk-path=vk.key --srs-path=15.srs +ezkl verify ``` This will return whether your proof has successfully verified or not. Refer to Verifying On-Chain section to verify with an EVM smart contract. [!ref](/verifying_on-chain) +For verifying in the browser refer to the verify section of the JS Bindings documentation. + +[!ref](/JS_Bindings/Verify.md) + _________________ -Note that these are not the only operations that can be performed by `ezkl`. You can also run a `Mock` proof to see if a proof will verify, or run the `Table` command to see a table of all your onnx operations that your SNARK will consist of. The table command is helpful in determining if `ezkl` knows how to snark your model. You can also run `Fuzz` to fuzz test your SNARK on random inputs. Even our EVM commands can take in `RunArgs` to specify how an evm verifier will be created. Let's look into the rest of these in detail. +Note that these are not the only operations that can be performed by `ezkl`. You can also run a `Mock` proof to see if a proof will verify, or run the `Table` command to see a table of all your onnx operations that your SNARK will consist of. The table command is helpful in determining if `ezkl` knows how to snark your model. You can also run `Fuzz` to fuzz test your SNARK on random inputs. Let's look into the rest of these in detail. ### Mock -When you're testing a model, you may not want to run `setup` and `prove` with each iteration. `ezkl` provides a simple alternative with `mock`, where you can convert your model to constraints and run the inputs tosee if a proof can be generated. This saves time when testing new iterations of models with potential issues. Here is the command for `mock`: +When you're testing a model, you may not want to run `setup` and `prove` with each iteration. `ezkl` provides a simple alternative with `mock`, where you can convert your model to constraints and run the inputs to see if a proof can be generated. This saves time when testing new iterations of models with potential issues. Here is the command for `mock`: ```bash -ezkl mock -M network.ezkl --witness witness.json +ezkl mock ``` Mock is basically checking that constraints that your model has been translated into are satisfied, without doing any of the subsequent cryptographic heavy lifting to produce a proof. -### Generate Witness - -The `gen-witness` function generates a witness for a given model and input data for a neural net or computational graph. A witness in the context of Zero Knowledge Proofs is a computational trace that allows a proof to be generated. The `gen-witness` function doesn't record all the intermediate values of the trace (such as the activations of inner layers in a neural network), but does write the final outputs of your neural network or computation graph in a form that is usable in the prove command, and human readable. - -The function has additional configurable settings, including an ONNX model file path, an input data file path, an output file path, an optional scale, and an optional batch size. More details on the optional scale and optional batch size can be found in [RunArgs](./RunArgs.md). - -```bash -ezkl gen-witness -M network.ezkl -D examples/onnx/1l_sigmoid/input.json -``` - ### Table `ezkl`'s `table` command enables users to get their model's operations, inputs, and outputs in an intuitive format. Calling this command: ```bash -ezkl table -M examples/onnx/1l_sigmoid/network.onnx +ezkl table ``` will produce a table that looks like: ```bash - | ┌─────────┬───────────┬────────┬──────────┬─────┐ - | │ opkind │ out_scale │ inputs │ out_dims │ idx │ - | ├─────────┼───────────┼────────┼──────────┼─────┤ - | │ Input │ 7 │ │ [1, 3] │ 0 │ - | ├─────────┼───────────┼────────┼──────────┼─────┤ - | │ SIGMOID │ 7 │ [0] │ [1, 3] │ 1 │ - | └─────────┴───────────┴────────┴──────────┴─────┘ + | + | ┌─────┬───────────────────────────────────────────────────────────────────────────────────────────────────┬───────────┬──────────────────┬──────────┐ + | │ idx │ opkind │ out_scale │ inputs │ out_dims │ + | ├─────┼───────────────────────────────────────────────────────────────────────────────────────────────────┼───────────┼──────────────────┼──────────┤ + | │ 0 │ Input │ 7 │ │ [1, 3] │ + | ├─────┼───────────────────────────────────────────────────────────────────────────────────────────────────┼───────────┼──────────────────┼──────────┤ + | │ 1 │ CONST (scale=7) │ 7 │ │ [4, 3] │ + | ├─────┼───────────────────────────────────────────────────────────────────────────────────────────────────┼───────────┼──────────────────┼──────────┤ + | │ 2 │ REBASED (div=128.0, rebasing_op=DIV (denom=128, use_range_check_for_int=true)) (EINSUM mk,nk->mn) │ 7 │ [(0, 0), (1, 0)] │ [1, 4] │ + | ├─────┼───────────────────────────────────────────────────────────────────────────────────────────────────┼───────────┼──────────────────┼──────────┤ + | │ 3 │ CONST (scale=7) │ 7 │ │ [1, 4] │ + | ├─────┼───────────────────────────────────────────────────────────────────────────────────────────────────┼───────────┼──────────────────┼──────────┤ + | │ 4 │ ADD │ 7 │ [(2, 0), (3, 0)] │ [1, 4] │ + | ├─────┼───────────────────────────────────────────────────────────────────────────────────────────────────┼───────────┼──────────────────┼──────────┤ + | │ 6 │ RELU │ 7 │ [(4, 0)] │ [1, 4] │ + | └─────┴───────────────────────────────────────────────────────────────────────────────────────────────────┴───────────┴──────────────────┴──────────┘ ``` You can use `table` with your model to know exactly which operations your model uses. If the operation is unsupported, you may see an `Unknown` in the table, and get a warning. This means the op isn't available in ezkl, and you should file an issue to request its implementation. @@ -219,13 +215,13 @@ Now, we can create our proof keys with `setup` (Note: be sure to use the same KZ ```bash # Conv ezkl compile-circuit -M examples/onnx/1l_conv/network.onnx --settings-path=circuitconv.json --compiled-circuit conv.ezkl -ezkl setup -M conv.ezkl --srs-path=23.srs --vk-path=vkconv.key --pk-path=pkconv.key +ezkl setup -M conv.ezkl --vk-path=vkconv.key --pk-path=pkconv.key ``` ```bash # Relu ezkl compile-circuit -M examples/onnx/1l_relu/network.onnx --settings-path=circuitrelu.json --compiled-circuit relu.ezkl -ezkl setup -M relu.ezkl --srs-path=23.srs --vk-path=vkrelu.key --pk-path=pkrelu.key +ezkl setup -M relu.ezkl --vk-path=vkrelu.key --pk-path=pkrelu.key ``` We then prove them. @@ -233,24 +229,24 @@ We then prove them. ```bash # Conv ezkl gen-witness -D ./examples/onnx/1l_conv/input.json -M conv.ezkl -O convwit.json -ezkl prove --proof-type=for-aggr --witness convwit.json -M conv.ezkl --proof-path conv.proof --srs-path=23.srs --pk-path=pkconv.key +ezkl prove --proof-type=for-aggr --witness convwit.json -M conv.ezkl --proof-path conv.proof --pk-path=pkconv.key ``` ```bash # Relu ezkl gen-witness -D ./examples/onnx/1l_relu/input.json -M relu.ezkl -O reluwit.json -ezkl prove --proof-type=for-aggr --witness reluwit.json -M relu.ezkl --proof-path relu.proof --srs-path=23.srs --pk-path=pkrelu.key +ezkl prove --proof-type=for-aggr --witness reluwit.json -M relu.ezkl --proof-path relu.proof --pk-path=pkrelu.key ``` Setup the aggregation: ```bash -ezkl setup-aggregate --sample-snarks conv.proof --sample-snarks relu.proof --srs-path 23.srs --logrows 23 +ezkl setup-aggregate --sample-snarks conv.proof --sample-snarks relu.proof --srs-path 23.srs ``` Now, we can aggregate the proofs: ```bash -ezkl aggregate --logrows=23 --aggregation-snarks=conv.proof --aggregation-snarks=relu.proof --proof-path aggr.proof --srs-path=23.srs --pk-path pk_aggr.key +ezkl aggregate --aggregation-snarks=conv.proof --aggregation-snarks=relu.proof --proof-path aggr.proof --srs-path=23.srs ``` This creates one proof that simultaneously proves both our `conv` and `relu` circuits as long as we pass both proofs and verifying keys in. The bad news is that computing an aggregation takes a lot of memory and time right now; this proof will probably take about two to five minutes depending on your machine. @@ -260,7 +256,7 @@ This creates one proof that simultaneously proves both our `conv` and `relu` cir Now, we can verify our aggregated proof with: ```bash -ezkl verify-aggr --logrows=23 --proof-path aggr.proof --srs-path=23.srs --vk-path vk_aggr.key +ezkl verify-aggr --proof-path aggr.proof --srs-path=23.srs ``` This should return `verified: true`. You can learn more about aggregation [here](https://vitalik.ca/general/2021/11/05/halo.html).