Zero-Knowledge Machine Learning (zkML)
An end-to-end workflow depicting how to use ezkl to generate and verify zero knowledge proofs for ML model outputs
Introduction
In our context, Zero-Knowledge Machine Learning (zkML) is the ability to verifiably prove that a given prediction did indeed come from a certain machine learning (ML) model claimed so by the modeler who trained that ML model.
There are two main players in the zkML game:
prover, who testifies that a given prediction is the output of a certain ML model
verifier, who verifies the correctness of the above proof
Please refer to our blog post for a detailed primer on zkML.
zkML in Practice
Practically speaking, all zkML approaches convert a trained ML model (M
) into its equivalent zk-circuit representation (M'
). Since the zk-circuit works with integers while floating point numbers are used in traditional ML techniques, there's bound to be a difference between the results of the ML model and its equivalent zk-circuit representation.
M'
resembles M
in terms of the architecture but differs in terms of the resultant model accuracy since:
All operations within
M'
are performed after quantizing all the involved tensors.In essence, quantization converts all floating point numbers to integers → directly impacting
M'
's accuracy (at the benefit of smaller size and faster inference time)
zkML then proves and verifies that M
was quantized which then produced a certain output after passing the quantized input feature vector through M'
.
Concretely, given a ML model M
that outputs y
:
zkML converts
M
to a quantized zk circuitM'
M'
produces an outputy'
zkML proves that the
y'
did indeed come fromM'
The difference between
y
andy'
is known as the Quantization Error
The above might appear to be counterintuitive to a traditional ML practitioner/data scientist, however:
This is in-line within the zkML landscape and is widely accepted by zkML practitioners
All ML models (specifically large models deployed on Edge devices) have to be transformed in one way or the other to allow:
for real-time or near-real-time predictions
them to be compatible with prod tech-stack and the edge devices Such transformations indeed change the predicted values in production/real-time environment compared to those in the dev/modelling environment.
Requires a mindset shift and general acceptance from the traditional ML practitioners whereby one needs to be willing to accept a level of compromise to implement zkML on top of their ML models and make their predictions zk-verifiable.
We require Modelers to use
y'
for all predictions returned during the Consumption Window
Recommendation
We recommend calculating the quantization error of your trained model (using the provided sample code, tailored to your circumstances) and making sure that the average of absolute errors across a handful of observations is not too high. If it is too high then experiment with another model architecture (with different operations) or adjust your zkML setup as explained in the Calibrate Settings section below.
Note that using the resources
calibration in ezkl.calibrate_settings()
will generally result in reasonable quantization errors, however there are certain operations (e.g., BatchNorm1d
) that will result in a higher quantization error compared to the models that don't include such operations.
zkML Library
Spectral has partnered with Zkonduit to allow the generation and verification of verifiable Zero-Knowledge Proofs on its platform. ezkl, one of Zkonduit’s zkML project, allows modelers to create zero-knowledge proofs of machine learning models imported using the Open Neural Network Exchange (ONNX).
Please refer to ezkl’s GitHub repo for further details, including some demo Jupyter Notebooks.
Overview of the zkML Workflow - using ezkl
At a high level, the end-to-end zkML workflow comprises of:
Setup
Train a ML model
PyTorch is natively supported and is thoroughly tested
Support for scikit-learn decision trees, random forests, and XGBoost has been recently added - we’re currently actively testing this
Export the trained ML model to the ONNX format through
torch.onnx.export()
Generate and calibrate a JSON settings file through
ezkl.generate_settings()
andezk.calibrate_settings()
respectively. These settings will then be used to create a quantized Halo2 circuit to represent the underlying ML modelSettings file is to be shared with the verifier
Compile the ONNX model through
ezkl.compile_circuit()
Fetch the Structured Reference String (SRS) required for zkML
SRS file is to be shared with the verifier
Setup ezkl through
ezkl.setup()
to create the proving and verifying keysVerifying key is to be shared with the verifier
Proof Generation
Generate a witness file through
ezkl.gen_witness()
Perform a mock run through
ezkl.mock()
as a sanity check of the steps performed so farGenerate a proof for a given model output through
ezkl.prove()
Proof file is to be shared with the verifier
Proof Verification
Verify a proof through
ezkl.verify()
ezkl Detailed Workflow - using PyTorch
Model Training
Train a PyTorch model as you would usually do.
Export to ONNX
Inputs required
Trained PyTorch Model
A random tensor of the same shape as the model input feature vector
Path where to save the resultant ONNX model
Output
ONNX model
Sample code
Install ezkl
Installing ezkl is as simple as pip install ezkl
.
Generate Settings
Inputs Required
model
: The saved ONNX model from the previous stepoutput
: Path where to save the resultant settings filepy_run_args
: Some of the key arguments for ezkl that can be specified are the following:input_visibility
: has to bepublic
in our use case, i.e., the model inputs are publicly known. The quantized field vector representation of these inputs are included in the proof file.output_visibility
: has to bepublic
in our use case, i.e., the model output is publicly known. The quantized field vector representation of the output is included in the proof file.param_visibility
: has to bepublic
in our use case, i.e., the trained model’s parameters are effectively baked into the zk-circuit and cannot be altered by the prover post proof generation. However, the model parameters are not visible in the proof file shared with the verifierbatch_size
: has to be 1 in our use case, i.e., proof for a single prediction is to be generated
Output
A JSON settings file. These settings dictate the parameters required to generate the zk-circuit.
Sample Code
Calibrate Settings
Inputs Required
data
: A JSON file containing a dictionary of the feature values with a key ofinput_data
. The dictionary values could either be a single set of feature values or multiple, all concatenated into a single list. These feature values will be used to calibrate the settings, therefore, they need to be as representative of the feature values as expected in the production (scaled values if the model expects to receive scaled values). The more data fed tocalibrate_settings
the more accurate (lower quantization errors) the resultant zk-circuit will be, albeit potentially at the cost of higher compute and memory requirements and longer proving times.
model
: The saved ONNX model from one of the previous stepssettings
: Settings file generated in the previous steptarget
: accepts one of the following values:resources
: Settings are calibrated to optimize the compute and proving time requirements together with smaller proof + proving key + verifying key file sizes at the cost of a relatively higher quantization erroraccuracy
: Settings are calibrated to minimize the quantization error at the cost of higher compute requirements, longer proving times, and much larger proof + proving key + verifying key file sizes
Refer to the Quantization Error section below for further details.
Output
Calibrated JSON settings file (the original settings file provided to
settings
is overwritten)
Sample Code
Notes
A fine balance needs to be achieved between the following:
compute requirements, proving time, and file sizes of the proof, verifying key, and proving key
quantization error
Strategies to find the right balance:
try both
resources
andaccuracy
for thetarget
argumentmanually adjust the
input_scale
,bits
, andlogrows
arguments in the generated settings file
Generally speaking, higher values for input_scales
is required for larger & more complex models or where minimal quantization error is required. These higher input_scales
values tend to require larger lookup tables → more bits to infill the lookup tables → requires more logrows → results in larger proving key file sizes → longer proving times.
ezkl Compile the zk-circuit
Inputs required
model
: The saved ONNX model from one of the previous stepscompiled_circuit
: Path where to save the resultant ezkl compiled zk-circuitsettings_path
: JSON of the calibrated settings file from the previous step
Output
Compiled zk-circuit, inclusive of the settings
Sample Code
Fetch SRS
Input required
srs_path
: Path where to save the resultant SRS filesettings_path
: JSON of the calibrated settings file from one of the previous steps
Output
JSON of the SRS
Sample code
Setup ezkl
Inputs required
model
: ezkl compiled zk-circuit from one of the previous stepsvk_path
: Path where to save the resultant verifying keypk_path
: Path where to save the resultant proving keysrs_path
: JSON of the SRS generated in the previous step
Output
Proving key
Verifying key
Sample code
Generate Witness file
Inputs required
data
: JSON of the input feature vector for which a proof is to be generated
model
: ezkl compiled zk-circuit from one of the previous stepsoutput
: Path where to save the resultant witness file
Output
JSON of the witness file
Sample code
Mock Run
Inputs required
witness
: JSON of the witness file from the previous stepmodel
: ezkl compiled zk-circuit from one of the previous steps
Output
Binary flag whether the mock run was successful or not
Sample code
Generate a Proof
Inputs required
witness
: JSON of the witness file from one of the previous stepsmodel
: ezkl compiled zk-circuit from one of the previous stepspk_path
: Proving Key from one of the previous stepsproof_path
: Path where to save the resultant proof filesrs_path
: JSON of the SRS from one of the previous stepsproof_type
: whether a single or an aggregated proof is required. possible values:single
andfor-aggr
Output
proof file
Sample code
Proof Verification
Inputs required
proof_path
: Proof file generated from the previous stepsettings_path
: JSON of the calibrated settings file from one of the previous stepsvk_path
: Verifying Key from one of the previous stepssrs_path
: JSON of the SRS from one of the previous steps
Output
Binary flag whether the proof verification was successful or not
Sample code
Calculate Quantization Errors
It is fairly straightforward to calculate and analyze the quantization error for multiple input feature vectors. The process essentially involves determining the zk-circuit output and that of the underlying ML model and comparing the difference between these two.
For a trained PyTorch model converted to an ONNX model that outputs predicted logits for a given input feature vector, the following code can be used to quantify the quantization error across multiple observations:
Last updated