mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
script/research/zkvm-metering: tools to generate and verify zk proofs containing single zkvm opcodes for resource usage measurement
This commit is contained in:
64
script/research/zkvm-metering/README.md
Normal file
64
script/research/zkvm-metering/README.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# ZkVM Metering tool
|
||||
- The aim of this tool is to analyze resource usage of ZkVM opcodes
|
||||
using [heaptrack](https://github.com/KDE/heaptrack).
|
||||
- We have a proof generator and verifier to profile each ZkVM Opcode.
|
||||
- The `generator` generates a proof, verifying key and public inputs
|
||||
for all the proofs stored in `generator/proof`.
|
||||
- Each Zk script file in `generator/proof` contains a single ZkVM
|
||||
opcode.
|
||||
- The `generator` saves it's outputs to disk for later use by the
|
||||
`verifier`.
|
||||
- The `verifier` loads the proof, verifying key and public inputs and
|
||||
verifies a single proof at a time identified by the opcode name.
|
||||
|
||||
#### Steps to profile a ZkVM Opcode
|
||||
|
||||
To generate the proofs go to `generator` directory and run these
|
||||
commands.
|
||||
```
|
||||
% make
|
||||
% ./generator
|
||||
```
|
||||
To verify the proof and profile all the opcodes go to `verifier` and
|
||||
run these commands. You need to install `heaptrack` before running the
|
||||
second command.
|
||||
```
|
||||
% make
|
||||
% ./run_heaptrack.sh
|
||||
```
|
||||
`run_heaptrack.sh` will generate `heaptrack` report for all the opcodes
|
||||
in `output` directory. If you prover to analyze a single opcode run
|
||||
the following.
|
||||
```
|
||||
% heaptrack ./verifer [OPCODE_NAME]
|
||||
```
|
||||
Once the `heaptrack` report is generated you can view it using `heaptrack_gui`.
|
||||
|
||||
#### Analysis Results
|
||||
|
||||
| # | Opcode | RAM Usage | Verifying Key Size | Proof Size |
|
||||
|----|-----------------------|-----------|--------------------|------------|
|
||||
| 0 | sparse_merkle_root | 17.1 MB | 1.2 MB | 7.7 kB |
|
||||
| 1 | merkle_root | 8.1 MB | 572.2 kB | 7.7 kB |
|
||||
| 2 | posedion_hash | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 3 | base_add | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 4 | base_mul | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 5 | base_sub | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 6 | ec_add | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 7 | ec_mul | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 8 | ec_mul_base | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 9 | ec_mul_short | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 10 | ec_mul_var_base | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 11 | ec_get_x | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 12 | ec_get_y | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 13 | constrain_instance | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 14 | constrain_equal_base | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 15 | constrain_equal_point | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 16 | bool_check | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 17 | cond_select | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 18 | zero_cond | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 19 | less_than_strict | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 20 | less_than_loose | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 21 | range_check | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 22 | witness_base | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
| 23 | debug | 2.4 MB | 145.6 kB | 7.6 kB |
|
||||
5
script/research/zkvm-metering/generator/.gitignore
vendored
Normal file
5
script/research/zkvm-metering/generator/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
rustfmt.toml
|
||||
generator
|
||||
*.bin
|
||||
26
script/research/zkvm-metering/generator/Cargo.toml
Normal file
26
script/research/zkvm-metering/generator/Cargo.toml
Normal file
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "generator"
|
||||
version = "0.1.0"
|
||||
description = "CLI-utility to generate zk proofs for analyzing zkvm opcodes resource usage"
|
||||
authors = ["Dyne.org foundation <foundation@dyne.org>"]
|
||||
repository = "https://codeberg.org/darkrenaissance/darkfi"
|
||||
license = "AGPL-3.0-only"
|
||||
edition = "2024"
|
||||
|
||||
[workspace]
|
||||
|
||||
[dependencies]
|
||||
darkfi-sdk = {path = "../../../../src/sdk"}
|
||||
darkfi = {path = "../../../../", features = ["zk"]}
|
||||
halo2_proofs = {version = "0.3.1", features = ["circuit-params"]}
|
||||
halo2_gadgets = {version = "0.3.1", features = ["circuit-params"]}
|
||||
rand = "0.8.5"
|
||||
darkfi-serial = "0.5.0"
|
||||
|
||||
[dev-dependencies]
|
||||
halo2_proofs = {version = "0.3.1", features = ["dev-graph", "sanity-checks"]}
|
||||
halo2_gadgets = "0.3.1"
|
||||
|
||||
[patch.crates-io]
|
||||
halo2_proofs = {git="https://github.com/parazyd/halo2", branch="v031"}
|
||||
halo2_gadgets = {git="https://github.com/parazyd/halo2", branch="v031"}
|
||||
48
script/research/zkvm-metering/generator/Makefile
Normal file
48
script/research/zkvm-metering/generator/Makefile
Normal file
@@ -0,0 +1,48 @@
|
||||
.POSIX:
|
||||
|
||||
# Install prefix
|
||||
PREFIX = $(HOME)/.cargo
|
||||
|
||||
# Cargo binary
|
||||
CARGO = cargo
|
||||
|
||||
# Compile target
|
||||
RUST_TARGET = $(shell rustc -Vv | grep '^host: ' | cut -d' ' -f2)
|
||||
# Uncomment when doing musl static builds
|
||||
#RUSTFLAGS = -C target-feature=+crt-static -C link-self-contained=yes
|
||||
|
||||
# zkas compiler binary
|
||||
ZKAS = ../../../../zkas
|
||||
|
||||
# zkas circuits
|
||||
PROOFS_SRC = $(shell find proof -type f -name '*.zk')
|
||||
PROOFS_BIN = $(PROOFS_SRC:=.bin)
|
||||
|
||||
SRC = \
|
||||
Cargo.toml \
|
||||
$(shell find src -type f -name '*.rs') \
|
||||
|
||||
BIN = $(shell grep '^name = ' Cargo.toml | cut -d' ' -f3 | tr -d '"')
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
$(PROOFS_BIN): $(ZKAS) $(PROOFS_SRC)
|
||||
$(ZKAS) $(basename $@) -o $@
|
||||
|
||||
$(BIN): $(PROOFS_BIN) $(SRC)
|
||||
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) build --target=$(RUST_TARGET) --release --package $@
|
||||
cp -f target/$(RUST_TARGET)/release/$@ $@
|
||||
|
||||
fmt:
|
||||
$(CARGO) +nightly fmt --all
|
||||
|
||||
clippy:
|
||||
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clippy --target=$(RUST_TARGET) \
|
||||
--release --all-features --workspace --tests
|
||||
|
||||
clean:
|
||||
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clean --target=$(RUST_TARGET) --release --package $(BIN)
|
||||
rm -f $(BIN)
|
||||
rm -f proof/*.bin
|
||||
|
||||
.PHONY: all fmt clippy clean
|
||||
14
script/research/zkvm-metering/generator/proof/base_add.zk
Normal file
14
script/research/zkvm-metering/generator/proof/base_add.zk
Normal file
@@ -0,0 +1,14 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "BaseAdd" {}
|
||||
|
||||
witness "BaseAdd" {
|
||||
Base a,
|
||||
Base b,
|
||||
}
|
||||
|
||||
circuit "BaseAdd" {
|
||||
sum = base_add(a, b);
|
||||
# constrain_instance(sum)
|
||||
}
|
||||
14
script/research/zkvm-metering/generator/proof/base_mul.zk
Normal file
14
script/research/zkvm-metering/generator/proof/base_mul.zk
Normal file
@@ -0,0 +1,14 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "BaseMul" {}
|
||||
|
||||
witness "BaseMul" {
|
||||
Base a,
|
||||
Base b,
|
||||
}
|
||||
|
||||
circuit "BaseMul" {
|
||||
product = base_mul(a, b);
|
||||
# constrain_instance(product)
|
||||
}
|
||||
14
script/research/zkvm-metering/generator/proof/base_sub.zk
Normal file
14
script/research/zkvm-metering/generator/proof/base_sub.zk
Normal file
@@ -0,0 +1,14 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "BaseSub" {}
|
||||
|
||||
witness "BaseSub" {
|
||||
Base a,
|
||||
Base b,
|
||||
}
|
||||
|
||||
circuit "BaseSub" {
|
||||
difference = base_sub(a, b);
|
||||
# constrain_instance(difference)
|
||||
}
|
||||
12
script/research/zkvm-metering/generator/proof/bool_check.zk
Normal file
12
script/research/zkvm-metering/generator/proof/bool_check.zk
Normal file
@@ -0,0 +1,12 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "BoolCheck" {}
|
||||
|
||||
witness "BoolCheck" {
|
||||
Base a,
|
||||
}
|
||||
|
||||
circuit "BoolCheck" {
|
||||
bool_check(a);
|
||||
}
|
||||
15
script/research/zkvm-metering/generator/proof/cond_select.zk
Normal file
15
script/research/zkvm-metering/generator/proof/cond_select.zk
Normal file
@@ -0,0 +1,15 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "CondSelect" {}
|
||||
|
||||
witness "CondSelect" {
|
||||
Base a,
|
||||
Base b,
|
||||
Base cond,
|
||||
}
|
||||
|
||||
circuit "CondSelect" {
|
||||
out = cond_select(cond, a, b);
|
||||
#constrain_instance(out);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "ConstrainEqualBase" {}
|
||||
|
||||
witness "ConstrainEqualBase" {
|
||||
Base a,
|
||||
Base b,
|
||||
}
|
||||
|
||||
circuit "ConstrainEqualBase" {
|
||||
constrain_equal_base(a, b);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "ConstrainEqualPoint" {}
|
||||
|
||||
witness "ConstrainEqualPoint" {
|
||||
EcPoint a,
|
||||
EcPoint b,
|
||||
}
|
||||
|
||||
circuit "ConstrainEqualPoint" {
|
||||
constrain_equal_point(a, b);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "ConstrainInstance" {}
|
||||
|
||||
witness "ConstrainInstance" {
|
||||
Base a,
|
||||
}
|
||||
|
||||
circuit "ConstrainInstance" {
|
||||
constrain_instance(a);
|
||||
}
|
||||
12
script/research/zkvm-metering/generator/proof/debug.zk
Normal file
12
script/research/zkvm-metering/generator/proof/debug.zk
Normal file
@@ -0,0 +1,12 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "Debug" {}
|
||||
|
||||
witness "Debug" {
|
||||
Base a,
|
||||
}
|
||||
|
||||
circuit "Debug" {
|
||||
debug(a);
|
||||
}
|
||||
15
script/research/zkvm-metering/generator/proof/ec_add.zk
Normal file
15
script/research/zkvm-metering/generator/proof/ec_add.zk
Normal file
@@ -0,0 +1,15 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "EcAdd" {}
|
||||
|
||||
witness "EcAdd" {
|
||||
EcPoint a,
|
||||
EcPoint b,
|
||||
}
|
||||
|
||||
circuit "EcAdd" {
|
||||
sum = ec_add(a, b);
|
||||
#constrain_instance(ec_get_x(sum));
|
||||
#constrain_instance(ec_get_y(sum));
|
||||
}
|
||||
13
script/research/zkvm-metering/generator/proof/ec_get_x.zk
Normal file
13
script/research/zkvm-metering/generator/proof/ec_get_x.zk
Normal file
@@ -0,0 +1,13 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "EcGetX" {}
|
||||
|
||||
witness "EcGetX" {
|
||||
EcPoint a,
|
||||
}
|
||||
|
||||
circuit "EcGetX" {
|
||||
a_x = ec_get_x(a);
|
||||
#constrain_instance(a_x);
|
||||
}
|
||||
13
script/research/zkvm-metering/generator/proof/ec_get_y.zk
Normal file
13
script/research/zkvm-metering/generator/proof/ec_get_y.zk
Normal file
@@ -0,0 +1,13 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "EcGetY" {}
|
||||
|
||||
witness "EcGetY" {
|
||||
EcPoint a,
|
||||
}
|
||||
|
||||
circuit "EcGetY" {
|
||||
a_y = ec_get_y(a);
|
||||
#constrain_instance(a_y);
|
||||
}
|
||||
16
script/research/zkvm-metering/generator/proof/ec_mul.zk
Normal file
16
script/research/zkvm-metering/generator/proof/ec_mul.zk
Normal file
@@ -0,0 +1,16 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "EcMul" {
|
||||
EcFixedPoint VALUE_COMMIT_RANDOM,
|
||||
}
|
||||
|
||||
witness "EcMul" {
|
||||
Scalar value_blind,
|
||||
}
|
||||
|
||||
circuit "EcMul" {
|
||||
vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
|
||||
#constrain_instance(ec_get_x(vcr));
|
||||
#constrain_instance(ec_get_y(vcr));
|
||||
}
|
||||
16
script/research/zkvm-metering/generator/proof/ec_mul_base.zk
Normal file
16
script/research/zkvm-metering/generator/proof/ec_mul_base.zk
Normal file
@@ -0,0 +1,16 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "EcMulBase" {
|
||||
EcFixedPointBase NULLIFIER_K,
|
||||
}
|
||||
|
||||
witness "EcMulBase" {
|
||||
Base secret,
|
||||
}
|
||||
|
||||
circuit "EcMulBase" {
|
||||
public = ec_mul_base(secret, NULLIFIER_K);
|
||||
#constrain_instance(ec_get_x(public));
|
||||
#constrain_instance(ec_get_y(public));
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "EcMulShort" {
|
||||
EcFixedPointShort VALUE_COMMIT_VALUE,
|
||||
}
|
||||
|
||||
witness "EcMulShort" {
|
||||
Base value,
|
||||
}
|
||||
|
||||
circuit "EcMulShort" {
|
||||
vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
|
||||
#constrain_instance(ec_get_x(vcv));
|
||||
#constrain_instance(ec_get_y(vcv));
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "EcMulVarBase" {
|
||||
}
|
||||
|
||||
witness "EcMulVarBase" {
|
||||
Base ephem_secret,
|
||||
EcNiPoint pubkey,
|
||||
}
|
||||
|
||||
circuit "EcMulVarBase" {
|
||||
ephem_public = ec_mul_var_base(ephem_secret, pubkey);
|
||||
constrain_instance(ec_get_x(ephem_public));
|
||||
constrain_instance(ec_get_y(ephem_public));
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "LessThanLoose" {}
|
||||
|
||||
witness "LessThanLoose" {
|
||||
Base a,
|
||||
Base b,
|
||||
}
|
||||
|
||||
circuit "LessThanLoose" {
|
||||
less_than_loose(a, b);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "LessThanStrict" {}
|
||||
|
||||
witness "LessThanStrict" {
|
||||
Base a,
|
||||
Base b,
|
||||
}
|
||||
|
||||
circuit "LessThanStrict" {
|
||||
less_than_strict(a, b);
|
||||
}
|
||||
17
script/research/zkvm-metering/generator/proof/merkle_root.zk
Normal file
17
script/research/zkvm-metering/generator/proof/merkle_root.zk
Normal file
@@ -0,0 +1,17 @@
|
||||
k = 13;
|
||||
field = "pallas";
|
||||
|
||||
constant "MerkleRoot" {
|
||||
}
|
||||
|
||||
witness "MerkleRoot" {
|
||||
Base leaf,
|
||||
Uint32 leaf_pos,
|
||||
MerklePath path,
|
||||
}
|
||||
|
||||
circuit "MerkleRoot" {
|
||||
root = merkle_root(leaf_pos, path, leaf);
|
||||
# constrain_instance(root)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "PoseidonHash" {}
|
||||
|
||||
witness "PoseidonHash" {
|
||||
Base a,
|
||||
Base b,
|
||||
}
|
||||
|
||||
circuit "PoseidonHash" {
|
||||
hash = poseidon_hash(a, b);
|
||||
#constrain_instance(hash);
|
||||
}
|
||||
12
script/research/zkvm-metering/generator/proof/range_check.zk
Normal file
12
script/research/zkvm-metering/generator/proof/range_check.zk
Normal file
@@ -0,0 +1,12 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "RangeCheck" {}
|
||||
|
||||
witness "RangeCheck" {
|
||||
Base a,
|
||||
}
|
||||
|
||||
circuit "RangeCheck" {
|
||||
range_check(64, a);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
k = 14;
|
||||
field = "pallas";
|
||||
|
||||
constant "SparseMerkleRoot" {
|
||||
}
|
||||
|
||||
witness "SparseMerkleRoot" {
|
||||
SparseMerklePath path,
|
||||
Base leaf,
|
||||
}
|
||||
|
||||
circuit "SparseMerkleRoot" {
|
||||
root = sparse_merkle_root(leaf, path, leaf);
|
||||
# constrain_instance(root)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "WitnessBase" {}
|
||||
|
||||
witness "WitnessBase" {
|
||||
}
|
||||
|
||||
circuit "WitnessBase" {
|
||||
two = witness_base(2);
|
||||
#constrain_instance(two);
|
||||
}
|
||||
14
script/research/zkvm-metering/generator/proof/zero_cond.zk
Normal file
14
script/research/zkvm-metering/generator/proof/zero_cond.zk
Normal file
@@ -0,0 +1,14 @@
|
||||
k = 11;
|
||||
field = "pallas";
|
||||
|
||||
constant "ZeroCond" {}
|
||||
|
||||
witness "ZeroCond" {
|
||||
Base a,
|
||||
Base b,
|
||||
}
|
||||
|
||||
circuit "ZeroCond" {
|
||||
out = zero_cond(a, b);
|
||||
#constrain_instance(out);
|
||||
}
|
||||
348
script/research/zkvm-metering/generator/src/main.rs
Normal file
348
script/research/zkvm-metering/generator/src/main.rs
Normal file
@@ -0,0 +1,348 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2025 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::{
|
||||
fs::{File, read_dir},
|
||||
io::{Read, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use darkfi::{
|
||||
zk::{Proof, ProvingKey, VerifyingKey, Witness, ZkCircuit, empty_witnesses, halo2::Field},
|
||||
zkas::ZkBinary,
|
||||
};
|
||||
use darkfi_sdk::{
|
||||
crypto::{
|
||||
MerkleNode, MerkleTree,
|
||||
constants::{
|
||||
NullifierK,
|
||||
OrchardFixedBasesFull::ValueCommitR,
|
||||
fixed_bases::{VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_V_BYTES},
|
||||
},
|
||||
pasta_prelude::{Curve, CurveAffine, CurveExt, Group},
|
||||
smt::{EMPTY_NODES_FP, MemoryStorageFp, PoseidonFp, SmtMemoryFp},
|
||||
util::{fp_mod_fv, poseidon_hash},
|
||||
},
|
||||
pasta::{Ep, Fp, Fq, pallas, pallas::Base},
|
||||
};
|
||||
use darkfi_serial::serialize;
|
||||
use halo2_gadgets::ecc::chip::FixedPoint;
|
||||
use halo2_proofs::circuit::Value;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
fn main() {
|
||||
let entries = read_dir("proof").unwrap();
|
||||
// Read each compiled zk file bin
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
if !(path.is_file() && path.to_str().unwrap().ends_with(".zk.bin")) {
|
||||
continue
|
||||
}
|
||||
let name = path.file_name().unwrap().to_str().unwrap().split(".").next().unwrap();
|
||||
let proof_file = format!("proof/{name}.proof.bin");
|
||||
let vk_file = format!("proof/{name}.vks.bin");
|
||||
let public_inputs_file = format!("proof/{name}.pi.bin");
|
||||
|
||||
// Skip if already generated
|
||||
if Path::new(&proof_file).exists() &&
|
||||
Path::new(&vk_file).exists() &&
|
||||
Path::new(&public_inputs_file).exists()
|
||||
{
|
||||
println!("{name} is already generated");
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("Generating {name} ...");
|
||||
|
||||
// Open zk bin
|
||||
let mut file = File::open(&path).unwrap();
|
||||
let mut buf = vec![];
|
||||
file.read_to_end(&mut buf).unwrap();
|
||||
let zkbin = ZkBinary::decode(&buf).unwrap();
|
||||
|
||||
// Get witnesses and public inputs for that particular zk file
|
||||
let (witnesses, public_inputs) = retrieve_proof_inputs(name);
|
||||
|
||||
// Generate and save Proof
|
||||
let circuit = ZkCircuit::new(witnesses, &zkbin);
|
||||
let proving_key = ProvingKey::build(zkbin.k, &circuit);
|
||||
let proof = Proof::create(&proving_key, &[circuit], &public_inputs, &mut OsRng).unwrap();
|
||||
|
||||
let proof_export = serialize(&proof);
|
||||
let mut f = File::create(&proof_file).unwrap();
|
||||
f.write_all(&proof_export).unwrap();
|
||||
|
||||
// Generate and save Verifying Key
|
||||
let verifier_witnesses = empty_witnesses(&zkbin).unwrap();
|
||||
let circuit = ZkCircuit::new(verifier_witnesses, &zkbin);
|
||||
let verifying_key = VerifyingKey::build(zkbin.k, &circuit);
|
||||
|
||||
let mut vk_export = vec![];
|
||||
verifying_key.write(&mut vk_export).unwrap();
|
||||
let mut f = File::create(&vk_file).unwrap();
|
||||
f.write_all(&vk_export).unwrap();
|
||||
|
||||
// Save Public inputs
|
||||
let public_inputs_export = serialize(&public_inputs);
|
||||
let mut f = File::create(&public_inputs_file).unwrap();
|
||||
f.write_all(&public_inputs_export).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn retrieve_proof_inputs(name: &str) -> (Vec<Witness>, Vec<Base>) {
|
||||
match name {
|
||||
"sparse_merkle_root" => {
|
||||
let hasher = PoseidonFp::new();
|
||||
let store = MemoryStorageFp::new();
|
||||
let mut smt = SmtMemoryFp::new(store, hasher.clone(), &EMPTY_NODES_FP);
|
||||
|
||||
let leaves =
|
||||
vec![Fp::random(&mut OsRng), Fp::random(&mut OsRng), Fp::random(&mut OsRng)];
|
||||
let leaves: Vec<_> = leaves.into_iter().map(|l| (l, l)).collect();
|
||||
smt.insert_batch(leaves.clone()).unwrap();
|
||||
|
||||
let (pos, leaf) = leaves[2];
|
||||
|
||||
let root = smt.root();
|
||||
let path = smt.prove_membership(&pos);
|
||||
|
||||
let prover_witnesses = vec![
|
||||
Witness::SparseMerklePath(Value::known(path.path)),
|
||||
Witness::Base(Value::known(leaf)),
|
||||
];
|
||||
|
||||
let public_inputs = vec![root];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"merkle_root" => {
|
||||
let mut tree = MerkleTree::new(u32::MAX as usize);
|
||||
let node1 = MerkleNode::from(Fp::random(&mut OsRng));
|
||||
let node2 = MerkleNode::from(Fp::random(&mut OsRng));
|
||||
let node3 = MerkleNode::from(Fp::random(&mut OsRng));
|
||||
tree.append(node1);
|
||||
tree.mark();
|
||||
tree.append(node2);
|
||||
let leaf_pos = tree.mark().unwrap();
|
||||
tree.append(node3);
|
||||
|
||||
let root = tree.root(0).unwrap().inner();
|
||||
let path = tree.witness(leaf_pos, 0).unwrap();
|
||||
|
||||
let prover_witnesses = vec![
|
||||
Witness::Base(Value::known(node2.inner())),
|
||||
Witness::Uint32(Value::known(u64::from(leaf_pos).try_into().unwrap())),
|
||||
Witness::MerklePath(Value::known(path.try_into().unwrap())),
|
||||
];
|
||||
let public_inputs = vec![root];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"base_add" => {
|
||||
let b1 = Fp::from(4u64);
|
||||
let b2 = Fp::from(110u64);
|
||||
let prover_witnesses =
|
||||
vec![Witness::Base(Value::known(b1)), Witness::Base(Value::known(b2))];
|
||||
let public_inputs = vec![b1 + b2];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"base_mul" => {
|
||||
let b1 = Fp::from(4u64);
|
||||
let b2 = Fp::from(110u64);
|
||||
let prover_witnesses =
|
||||
vec![Witness::Base(Value::known(b1)), Witness::Base(Value::known(b2))];
|
||||
let public_inputs = vec![b1 * b2];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"base_sub" => {
|
||||
let b1 = Fp::from(4u64);
|
||||
let b2 = Fp::from(110u64);
|
||||
let prover_witnesses =
|
||||
vec![Witness::Base(Value::known(b1)), Witness::Base(Value::known(b2))];
|
||||
let public_inputs = vec![b1 - b2];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"ec_add" => {
|
||||
let p1 = Ep::random(&mut OsRng);
|
||||
let p2 = Ep::random(&mut OsRng);
|
||||
let sum = (p1 + p2).to_affine();
|
||||
let sum_x = *sum.coordinates().unwrap().x();
|
||||
let sum_y = *sum.coordinates().unwrap().y();
|
||||
let prover_witnesses =
|
||||
vec![Witness::EcPoint(Value::known(p1)), Witness::EcPoint(Value::known(p2))];
|
||||
let public_inputs = vec![sum_x, sum_y];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"ec_mul" => {
|
||||
let scalar_blind = Fq::random(&mut OsRng);
|
||||
let vcr = (ValueCommitR.generator() * scalar_blind).to_affine();
|
||||
let vcr_x = *vcr.coordinates().unwrap().x();
|
||||
let vcr_y = *vcr.coordinates().unwrap().y();
|
||||
let prover_witnesses = vec![Witness::Scalar(Value::known(scalar_blind))];
|
||||
let public_inputs = vec![vcr_x, vcr_y];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"ec_mul_base" => {
|
||||
let secret_key = Fp::random(&mut OsRng);
|
||||
let pubkey = (NullifierK.generator() * fp_mod_fv(secret_key)).to_affine();
|
||||
let pubkey_x = *pubkey.coordinates().unwrap().x();
|
||||
let pubkey_y = *pubkey.coordinates().unwrap().y();
|
||||
let prover_witnesses = vec![Witness::Base(Value::known(secret_key))];
|
||||
let public_inputs = vec![pubkey_x, pubkey_y];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"ec_mul_short" => {
|
||||
// we can't use Fp::random() since it can be more than u64::MAX and we need value to be u64
|
||||
let value = Fp::from(42);
|
||||
let hasher = pallas::Point::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
|
||||
let val_commit = hasher(&VALUE_COMMITMENT_V_BYTES);
|
||||
|
||||
let vcv = (val_commit * fp_mod_fv(value)).to_affine();
|
||||
let vcv_x = *vcv.coordinates().unwrap().x();
|
||||
let vcv_y = *vcv.coordinates().unwrap().y();
|
||||
let prover_witnesses = vec![Witness::Base(Value::known(value))];
|
||||
let public_inputs = vec![vcv_x, vcv_y];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"ec_mul_var_base" => {
|
||||
let ephem_secret = Fp::random(&mut OsRng);
|
||||
let pubkey = NullifierK.generator() * fp_mod_fv(ephem_secret);
|
||||
let ephem_pub = (pubkey * fp_mod_fv(ephem_secret)).to_affine();
|
||||
let ephem_pub_x = *ephem_pub.coordinates().unwrap().x();
|
||||
let ephem_pub_y = *ephem_pub.coordinates().unwrap().y();
|
||||
let prover_witnesses = vec![
|
||||
Witness::Base(Value::known(ephem_secret)),
|
||||
Witness::EcNiPoint(Value::known(pubkey)),
|
||||
];
|
||||
let public_inputs = vec![ephem_pub_x, ephem_pub_y];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"ec_get_x" => {
|
||||
let p = Ep::random(&mut OsRng);
|
||||
let x = *p.to_affine().coordinates().unwrap().x();
|
||||
let prover_witnesses = vec![Witness::EcPoint(Value::known(p))];
|
||||
let public_inputs = vec![x];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"ec_get_y" => {
|
||||
let p = Ep::random(&mut OsRng);
|
||||
let y = *p.to_affine().coordinates().unwrap().y();
|
||||
let prover_witnesses = vec![Witness::EcPoint(Value::known(p))];
|
||||
let public_inputs = vec![y];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"poseidon_hash" => {
|
||||
let a = Fp::random(&mut OsRng);
|
||||
let b = Fp::random(&mut OsRng);
|
||||
let hash = poseidon_hash([a, b]);
|
||||
let prover_witnesses =
|
||||
vec![Witness::Base(Value::known(a)), Witness::Base(Value::known(b))];
|
||||
let public_inputs = vec![hash];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"constrain_instance" => {
|
||||
let a = Fp::random(&mut OsRng);
|
||||
let prover_witnesses = vec![Witness::Base(Value::known(a))];
|
||||
let public_inputs = vec![a];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"witness_base" => (vec![], vec![Fp::from(2)]),
|
||||
"constrain_equal_base" => {
|
||||
let a = Fp::from(23);
|
||||
let prover_witnesses =
|
||||
vec![Witness::Base(Value::known(a)), Witness::Base(Value::known(a))];
|
||||
|
||||
(prover_witnesses, vec![])
|
||||
}
|
||||
"constrain_equal_point" => {
|
||||
let a = Ep::random(&mut OsRng);
|
||||
let prover_witnesses =
|
||||
vec![Witness::EcPoint(Value::known(a)), Witness::EcPoint(Value::known(a))];
|
||||
|
||||
(prover_witnesses, vec![])
|
||||
}
|
||||
"less_than_strict" => {
|
||||
let a = Fp::from(23);
|
||||
let b = Fp::from(42);
|
||||
let prover_witnesses =
|
||||
vec![Witness::Base(Value::known(a)), Witness::Base(Value::known(b))];
|
||||
|
||||
(prover_witnesses, vec![])
|
||||
}
|
||||
"less_than_loose" => {
|
||||
let a = Fp::from(23);
|
||||
let prover_witnesses =
|
||||
vec![Witness::Base(Value::known(a)), Witness::Base(Value::known(a))];
|
||||
|
||||
(prover_witnesses, vec![])
|
||||
}
|
||||
"bool_check" => {
|
||||
let a = Fp::from(1);
|
||||
let prover_witnesses = vec![Witness::Base(Value::known(a))];
|
||||
|
||||
(prover_witnesses, vec![])
|
||||
}
|
||||
"cond_select" => {
|
||||
let a = Fp::from(23);
|
||||
let b = Fp::from(42);
|
||||
let cond = Fp::from(1);
|
||||
let prover_witnesses = vec![
|
||||
Witness::Base(Value::known(a)),
|
||||
Witness::Base(Value::known(b)),
|
||||
Witness::Base(Value::known(cond)),
|
||||
];
|
||||
let public_inputs = vec![a];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"zero_cond" => {
|
||||
let a = Fp::from(0);
|
||||
let b = Fp::from(23);
|
||||
let prover_witnesses =
|
||||
vec![Witness::Base(Value::known(a)), Witness::Base(Value::known(b))];
|
||||
let public_inputs = vec![a];
|
||||
|
||||
(prover_witnesses, public_inputs)
|
||||
}
|
||||
"range_check" => {
|
||||
let a = Fp::from(23);
|
||||
let prover_witnesses = vec![Witness::Base(Value::known(a))];
|
||||
|
||||
(prover_witnesses, vec![])
|
||||
}
|
||||
"debug" => {
|
||||
let a = Fp::from(23);
|
||||
let prover_witnesses = vec![Witness::Base(Value::known(a))];
|
||||
|
||||
(prover_witnesses, vec![])
|
||||
}
|
||||
_ => panic!("unsupported Zk script"),
|
||||
}
|
||||
}
|
||||
5
script/research/zkvm-metering/verifier/.gitignore
vendored
Normal file
5
script/research/zkvm-metering/verifier/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
rustfmt.toml
|
||||
verifier
|
||||
*.zst
|
||||
22
script/research/zkvm-metering/verifier/Cargo.toml
Normal file
22
script/research/zkvm-metering/verifier/Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "verifier"
|
||||
version = "0.1.0"
|
||||
description = "CLI-utility to verify zk proofs for analysis"
|
||||
authors = ["Dyne.org foundation <foundation@dyne.org>"]
|
||||
repository = "https://codeberg.org/darkrenaissance/darkfi"
|
||||
license = "AGPL-3.0-only"
|
||||
edition = "2024"
|
||||
|
||||
[workspace]
|
||||
|
||||
[dependencies]
|
||||
darkfi-sdk = {path = "../../../../src/sdk"}
|
||||
darkfi = {path = "../../../../", features = ["zk"]}
|
||||
darkfi-serial = "0.5.0"
|
||||
|
||||
[patch.crates-io]
|
||||
halo2_proofs = {git="https://github.com/parazyd/halo2", branch="v031"}
|
||||
halo2_gadgets = {git="https://github.com/parazyd/halo2", branch="v031"}
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
37
script/research/zkvm-metering/verifier/Makefile
Normal file
37
script/research/zkvm-metering/verifier/Makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
.POSIX:
|
||||
|
||||
# Install prefix
|
||||
PREFIX = $(HOME)/.cargo
|
||||
|
||||
# Cargo binary
|
||||
CARGO = cargo
|
||||
|
||||
# Compile target
|
||||
RUST_TARGET = $(shell rustc -Vv | grep '^host: ' | cut -d' ' -f2)
|
||||
# Uncomment when doing musl static builds
|
||||
#RUSTFLAGS = -C target-feature=+crt-static -C link-self-contained=yes
|
||||
|
||||
SRC = \
|
||||
Cargo.toml \
|
||||
$(shell find src -type f -name '*.rs') \
|
||||
|
||||
BIN = $(shell grep '^name = ' Cargo.toml | cut -d' ' -f3 | tr -d '"')
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
$(BIN): $(SRC)
|
||||
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) build --target=$(RUST_TARGET) --release --package $@
|
||||
cp -f target/$(RUST_TARGET)/release/$@ $@
|
||||
|
||||
fmt:
|
||||
$(CARGO) +nightly fmt --all
|
||||
|
||||
clippy:
|
||||
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clippy --target=$(RUST_TARGET) \
|
||||
--release --all-features --workspace --tests
|
||||
|
||||
clean:
|
||||
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) clean --target=$(RUST_TARGET) --release --package $(BIN)
|
||||
rm -f $(BIN)
|
||||
|
||||
.PHONY: all fmt clippy clean
|
||||
10
script/research/zkvm-metering/verifier/run_heaptrack.sh
Executable file
10
script/research/zkvm-metering/verifier/run_heaptrack.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
SRC_DIR="../generator/proof"
|
||||
|
||||
for file in "$SRC_DIR"/*.zk; do
|
||||
filename=$(basename "$file")
|
||||
name="${filename%.zk}"
|
||||
|
||||
heaptrack --output "output/${name}" ./verifier "$name"
|
||||
done
|
||||
75
script/research/zkvm-metering/verifier/src/main.rs
Normal file
75
script/research/zkvm-metering/verifier/src/main.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2025 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::{
|
||||
env,
|
||||
fs::File,
|
||||
io::{Cursor, Read},
|
||||
};
|
||||
|
||||
use darkfi::{
|
||||
Result,
|
||||
zk::{Proof, VerifyingKey, ZkCircuit, empty_witnesses},
|
||||
zkas::ZkBinary,
|
||||
};
|
||||
use darkfi_sdk::pasta::pallas::Base;
|
||||
use darkfi_serial::deserialize;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() != 2 {
|
||||
println!("Usage: ./verifier opcode_name");
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let file_name = &args[1];
|
||||
|
||||
let name = file_name.split(".").next().unwrap();
|
||||
//Load zkbin, proof, verifying key, public inputs from file
|
||||
let mut file = File::open(format!("../generator/proof/{name}.zk.bin"))?;
|
||||
let mut bincode = vec![];
|
||||
file.read_to_end(&mut bincode)?;
|
||||
|
||||
let mut file = File::open(format!("../generator/proof/{name}.proof.bin"))?;
|
||||
let mut proof_bin = vec![];
|
||||
file.read_to_end(&mut proof_bin)?;
|
||||
|
||||
let mut file = File::open(format!("../generator/proof/{name}.vks.bin"))?;
|
||||
let mut vkbin = vec![];
|
||||
file.read_to_end(&mut vkbin)?;
|
||||
|
||||
let mut file = File::open(format!("../generator/proof/{name}.pi.bin"))?;
|
||||
let mut public_inputs_bin = vec![];
|
||||
file.read_to_end(&mut public_inputs_bin)?;
|
||||
|
||||
// Deserialize and Verify
|
||||
let zkbin = ZkBinary::decode(&bincode)?;
|
||||
let verifier_witnesses = empty_witnesses(&zkbin)?;
|
||||
|
||||
// Create the circuit
|
||||
let circuit = ZkCircuit::new(verifier_witnesses, &zkbin);
|
||||
|
||||
let proof: Proof = deserialize(&proof_bin)?;
|
||||
let mut vk_buf = Cursor::new(vkbin);
|
||||
let vk = VerifyingKey::read::<Cursor<Vec<u8>>, ZkCircuit>(&mut vk_buf, circuit)?;
|
||||
//let vk = VerifyingKey::build(zkbin.k, &circuit);
|
||||
|
||||
let public_inputs: Vec<Base> = deserialize(&public_inputs_bin)?;
|
||||
|
||||
Ok(proof.verify(&vk, &public_inputs)?)
|
||||
}
|
||||
Reference in New Issue
Block a user