Skip to content

Commit

Permalink
Merge pull request #82 from okx/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
RUAN0007 authored Sep 9, 2024
2 parents 90b801a + 595a181 commit 940b19b
Show file tree
Hide file tree
Showing 25 changed files with 2,193 additions and 1,497 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ test-data/user-data*/
test-data/proofs*/
my_permanent_leveldb/
*level_db*/
*.json
*.json
*DS_Store
*tar
release/
2 changes: 2 additions & 0 deletions config/default.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[prover]
round_no = 0
user_data_path = "/opt/data/zkpor/users/"
batch_prove_threads_num = 32
recursive_prove_threads_num = 16

tokens = [ "BTC", "ETH", "USDT", "USDC", "XRP", "DOGE", "SOL", "OKB", "APT", "DASH", "DOT", "ELF", "EOS", "ETC", "FIL", "LINK", "LTC", "OKT", "PEOPLE", "TON", "TRX", "UNI", "1INCH", "AAVE", "ADA", "AGLD", "AIDOGE", "AKITA", "ALGO", "ALPHA", "ANT", "APE", "API3", "AR", "ARB", "ATOM", "AVAX", "AXS", "BABYDOGE", "BADGER", "BAL", "BAND", "BAT", "BCH", "BETH", "BICO", "BLUR", "BNB", "BNT", "BSV", "BTM", "BZZ", "CEL", "CELO", "CELR", "CETUS", "CFX", "CHZ", "CLV", "COMP", "CONV", "CORE", "CQT", "CRO", "CRV", "CSPR", "CVC", "DOME", "DORA", "DYDX", "EFI", "EGLD", "ENJ", "ENS", "ETHW", "FITFI", "FLM", "FLOKI", "FLOW", "FTM", "GALA", "GFT", "GLMR", "GMT", "GMX", "GODS", "GRT", "HBAR", "ICP", "IMX", "IOST", "IOTA", "JST", "KISHU", "KLAY", "KNC", "KSM", "LAT", "LDO", "LON", "LOOKS", "LPT", "LRC", "LUNA", "LUNC", "MAGIC", "MANA", "MASK", "MATIC", "MINA", "MKR", "NEAR", "NEO", "NFT", "OMG", "ONT", "OP", "PEPE", "PERP", "QTUM", "RDNT", "REN", "RSR", "RSS3", "RVN", "SAND", "SHIB", "SKL", "SLP", "SNT", "SNX", "STARL", "STORJ", "STX", "SUI", "SUSHI", "SWEAT", "SWRV", "THETA", "TRB", "TUSD", "UMA", "USTC", "WAVES", "WOO", "XCH", "XLM", "XMR", "XTZ", "YFI", "YFII", "YGG", "ZEC", "ZEN", "ZIL", "ZRX", "BTC1", "ETH1", "USDT1", "USDC1", "XRP1", "DOGE1", "SOL1", "OKB1", "APT1", "DASH1", "DOT1", "ELF1", "EOS1", "ETC1", "FIL1", "LINK1", "BTC2", "ETH2", "USDT2", "USDC2", "XRP2", "DOGE2", "SOL2", "OKB2", "APT2", "DASH2", "DOT2", "ELF2", "EOS2", "ETC2", "FIL2", "LINK2", "BTC3", "ETH3", "USDT3", "USDC3", "XRP3", "DOGE3", "SOL3", "OKB3", "APT3", "DASH3", "DOT3", "ELF3", "EOS3", "ETC3", "FIL3", "LINK3", "BTC4", "ETH4", "USDT4", "USDC4", "XRP4", "DOGE4", "SOL4", "OKB4", "APT4", "DASH4", "DOT4", "ELF4", "EOS4", "ETC4", "FIL4", "LINK4" ]

Expand Down
4 changes: 2 additions & 2 deletions crates/zk-por-cli/src/constant.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub const RECURSION_BRANCHOUT_NUM: usize = 64;
pub const BATCH_PROVING_THREADS_NUM: usize = 2;
pub const RECURSIVE_PROVING_THREADS_NUM: usize = 2;
pub const DEFAULT_BATCH_SIZE: usize = 1024;
pub const GLOBAL_PROOF_FILENAME: &str = "global_proof.json";
pub const GLOBAL_INFO_FILENAME: &str = "global_info.json";
pub const USER_PROOF_DIRNAME: &str = "user_proofs";
pub const DEFAULT_USER_PROOF_FILE_PATTERN: &str = "*_inclusion_proof.json";
2 changes: 1 addition & 1 deletion crates/zk-por-cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
mod constant;
pub mod constant;
pub mod prover;
pub mod verifier;
46 changes: 34 additions & 12 deletions crates/zk-por-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::{path::PathBuf, str::FromStr};

use clap::{Parser, Subcommand};
use zk_por_cli::{
constant::{DEFAULT_USER_PROOF_FILE_PATTERN, GLOBAL_PROOF_FILENAME},
prover::prove,
verifier::{verify_global, verify_user},
};
Expand All @@ -11,7 +12,7 @@ use zk_por_core::error::PoRError;
#[command(version, about, long_about = None)]
struct Cli {
#[command(subcommand)]
command: ZkPorCommitCommands,
command: Option<ZkPorCommitCommands>,
}

pub trait Execute {
Expand Down Expand Up @@ -39,34 +40,55 @@ pub enum ZkPorCommitCommands {
},
}

impl Execute for ZkPorCommitCommands {
impl Execute for Option<ZkPorCommitCommands> {
fn execute(&self) -> std::result::Result<(), PoRError> {
match self {
ZkPorCommitCommands::Prove { cfg_path, output_path } => {
Some(ZkPorCommitCommands::Prove { cfg_path, output_path }) => {
let cfg = zk_por_core::config::ProverConfig::load(&cfg_path)
.map_err(|e| PoRError::ConfigError(e))?;
let prover_cfg = cfg.try_deserialize().unwrap();
let output_file = PathBuf::from_str(&output_path).unwrap();
prove(prover_cfg, output_file)
let output_path = PathBuf::from_str(&output_path).unwrap();
prove(prover_cfg, output_path)
}

ZkPorCommitCommands::VerifyGlobal { proof_path: global_proof_path } => {
Some(ZkPorCommitCommands::VerifyGlobal { proof_path: global_proof_path }) => {
let global_proof_path = PathBuf::from_str(&global_proof_path).unwrap();
verify_global(global_proof_path)
verify_global(global_proof_path, true)
}

ZkPorCommitCommands::VerifyUser { global_proof_path, user_proof_path_pattern } => {
Some(ZkPorCommitCommands::VerifyUser {
global_proof_path,
user_proof_path_pattern,
}) => {
let global_proof_path = PathBuf::from_str(&global_proof_path).unwrap();
verify_user(global_proof_path, user_proof_path_pattern)
verify_user(global_proof_path, user_proof_path_pattern, true)
}

None => {
println!("============Validation started============");
let global_proof_path = PathBuf::from_str(GLOBAL_PROOF_FILENAME).unwrap();
let user_proof_path_pattern = DEFAULT_USER_PROOF_FILE_PATTERN.to_owned();
if verify_global(global_proof_path.clone(), false).is_ok() {
println!("Total sum and non-negative constraint validation passed")
} else {
println!("Total sum and non-negative constraint validation failed")
}

if verify_user(global_proof_path, &user_proof_path_pattern, false).is_ok() {
println!("Inclusion constraint validation passed")
} else {
println!("Inclusion constraint validation failed")
}
println!("============Validation finished============");
Ok(())
}
}
}
}

fn main() -> std::result::Result<(), PoRError> {
let cli = Cli::parse();
let start = std::time::Instant::now();
let result = cli.command.execute();
println!("result: {:?}, elapsed: {:?}", result, start.elapsed());
let r = cli.command.execute();
println!("Execution result: {:?}", r);
Ok(())
}
64 changes: 49 additions & 15 deletions crates/zk-por-cli/src/prover.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use super::constant::{
BATCH_PROVING_THREADS_NUM, DEFAULT_BATCH_SIZE, GLOBAL_PROOF_FILENAME, RECURSION_BRANCHOUT_NUM,
RECURSIVE_PROVING_THREADS_NUM, USER_PROOF_DIRNAME,
DEFAULT_BATCH_SIZE, GLOBAL_INFO_FILENAME, GLOBAL_PROOF_FILENAME, RECURSION_BRANCHOUT_NUM,
USER_PROOF_DIRNAME,
};
use indicatif::ProgressBar;
use plonky2::hash::hash_types::HashOut;
use plonky2_field::types::PrimeField64;
use rayon::{iter::ParallelIterator, prelude::*};
use serde_json::json;
use std::{
Expand All @@ -29,15 +30,14 @@ use zk_por_core::{
parser::{AccountParser, FileAccountReader, FileManager, FilesCfg},
recursive_prover::recursive_circuit::RecursiveTargets,
types::F,
General, Proof,
General, Info, Proof,
};
use zk_por_tracing::{init_tracing, TraceConfig};

// as we use one thread to prove each batch, we load num_cpus batches to increase the parallelism.
fn calculate_per_parse_account_num(batch_size: usize) -> usize {
fn calculate_per_parse_account_num(batch_size: usize, threads_num: usize) -> usize {
let num_cpus = num_cpus::get();
let num_cpus =
if BATCH_PROVING_THREADS_NUM < num_cpus { BATCH_PROVING_THREADS_NUM } else { num_cpus };
let num_cpus = if threads_num < num_cpus { threads_num } else { num_cpus };
num_cpus * batch_size
}

Expand Down Expand Up @@ -76,6 +76,9 @@ pub fn prove(cfg: ProverConfig, proof_output_path: PathBuf) -> Result<(), PoRErr

let batch_size = cfg.prover.batch_size.unwrap_or(DEFAULT_BATCH_SIZE);
let token_num = cfg.prover.tokens.len();
let batch_prove_threads_num = cfg.prover.batch_prove_threads_num;
let recursive_prove_threads_num = cfg.prover.recursive_prove_threads_num;

// the path to dump the final generated proof
let file_manager = FileManager {};
let mut account_parser = FileAccountReader::new(
Expand Down Expand Up @@ -127,7 +130,8 @@ pub fn prove(cfg: ProverConfig, proof_output_path: PathBuf) -> Result<(), PoRErr

let start = std::time::Instant::now();
let mut offset = 0;
let per_parse_account_num = calculate_per_parse_account_num(batch_size);
let per_parse_account_num =
calculate_per_parse_account_num(batch_size, batch_prove_threads_num);

let mut parse_num = 0;
let mut batch_proofs = vec![];
Expand Down Expand Up @@ -178,12 +182,8 @@ pub fn prove(cfg: ProverConfig, proof_output_path: PathBuf) -> Result<(), PoRErr
.collect();
drop(_g);

let proofs = batch_prove_accounts(
&circuit_registry,
accounts,
BATCH_PROVING_THREADS_NUM,
batch_size,
);
let proofs =
batch_prove_accounts(&circuit_registry, accounts, batch_prove_threads_num, batch_size);

assert_eq!(proofs.len(), root_hashes.len());

Expand Down Expand Up @@ -267,7 +267,7 @@ pub fn prove(cfg: ProverConfig, proof_output_path: PathBuf) -> Result<(), PoRErr
last_level_proofs,
last_level_circuit_vd.clone(),
&circuit_registry,
RECURSIVE_PROVING_THREADS_NUM,
recursive_prove_threads_num,
level,
);

Expand Down Expand Up @@ -369,6 +369,39 @@ fn dump_proofs(
.write_all(json!(root_proof).to_string().as_bytes())
.map_err(|e| return PoRError::Io(e))?;

///////////////////////////////////////////////
let hash_offset = RecursiveTargets::<RECURSION_BRANCHOUT_NUM>::pub_input_hash_offset();
let root_hash = HashOut::<F>::from_partial(&root_proof.proof.public_inputs[hash_offset]);
let root_hash_bytes = root_hash
.elements
.iter()
.map(|x| x.to_canonical_u64().to_le_bytes())
.flatten()
.collect::<Vec<u8>>();
let root_hash = hex::encode(root_hash_bytes);

let equity_offset = RecursiveTargets::<RECURSION_BRANCHOUT_NUM>::pub_input_equity_offset();
let equity_sum = root_proof.proof.public_inputs[equity_offset].to_canonical_u64();

let debt_offset = RecursiveTargets::<RECURSION_BRANCHOUT_NUM>::pub_input_debt_offset();
let debt_sum = root_proof.proof.public_inputs[debt_offset].to_canonical_u64();
assert!(equity_sum >= debt_sum);
let balance_sum = equity_sum - debt_sum;
let info = Info {
root_hash: root_hash,
equity_sum: equity_sum,
debt_sum: debt_sum,
balance_sum: balance_sum,
};

let global_info_output_path = proof_output_dir_path.join(GLOBAL_INFO_FILENAME);
let mut global_info_file =
File::create(global_info_output_path.clone()).map_err(|e| PoRError::Io(e))?;

global_info_file
.write_all(json!(info).to_string().as_bytes())
.map_err(|e| return PoRError::Io(e))?;

///////////////////////////////////////////////
// generate and dump proof for each user
// create a new account reader to avoid buffering previously loaded accounts in memory
Expand All @@ -394,7 +427,8 @@ fn dump_proofs(
tracing::info!("start to generate and dump merkle proof for each of {} accounts", user_num);

let bar = ProgressBar::new(user_num as u64);
let per_parse_account_num = calculate_per_parse_account_num(batch_size);
let per_parse_account_num =
calculate_per_parse_account_num(batch_size, cfg.batch_prove_threads_num);

let cdb: Arc<dyn PoRDB> = Arc::from(db);
let mut offset = 0;
Expand Down
96 changes: 65 additions & 31 deletions crates/zk-por-cli/src/verifier.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use indicatif::ProgressBar;
use plonky2_field::types::PrimeField64;
use rayon::iter::IntoParallelRefIterator;
use serde_json::from_reader;
use std::{fs::File, path::PathBuf};
Expand Down Expand Up @@ -38,6 +39,7 @@ fn find_matching_files(pattern: &str) -> Result<Vec<PathBuf>, io::Error> {
pub fn verify_user(
global_proof_path: PathBuf,
user_proof_path_pattern: &String,
verbose: bool,
) -> Result<(), PoRError> {
let proof_file = File::open(&global_proof_path).unwrap();
let reader = std::io::BufReader::new(proof_file);
Expand All @@ -51,34 +53,55 @@ pub fn verify_user(
let user_proof_paths =
find_matching_files(user_proof_path_pattern).map_err(|e| PoRError::Io(e))?;
let proof_file_num = user_proof_paths.len();
println!("successfully identify {} user proof files", proof_file_num);
if proof_file_num == 0 {
return Err(PoRError::InvalidParameter(format!(
"fail to find any user proof files with pattern {}",
user_proof_path_pattern
)));
}

if verbose {
println!("successfully identify {} user proof files", proof_file_num);
}

let bar = ProgressBar::new(proof_file_num as u64);
let chunk_size: usize = num_cpus::get();
user_proof_paths.chunks(chunk_size).for_each(|chunks| {
chunks.par_iter().for_each(|user_proof_path| {
let invalid_proof_paths = user_proof_paths
.par_iter()
.map(|user_proof_path| {
let merkle_path = File::open(&user_proof_path).unwrap();
let reader = std::io::BufReader::new(merkle_path);
let proof: MerkleProof = from_reader(reader).unwrap();
if let Err(e) = proof.verify_merkle_proof(root_hash) {
panic!(
"fail to verify the user proof on path {:?} due to error {:?}",
user_proof_path, e
)
let result = proof.verify_merkle_proof(root_hash);
if verbose {
bar.inc(1);
}
});
bar.inc(chunks.len() as u64);
});
bar.finish();
println!(
"successfully verify {} user proofs with file pattern {}",
proof_file_num, user_proof_path_pattern
);
(result, user_proof_path)
})
.filter(|(result, _)| result.is_err())
.map(|(_, invalid_proof_path)| invalid_proof_path.to_str().unwrap().to_owned())
.collect::<Vec<String>>();
if verbose {
bar.finish();
}

let invalid_proof_num = invalid_proof_paths.len();
let valid_proof_num = proof_file_num - invalid_proof_num;
if verbose {
let max_to_display_valid_proof_num = 10;

println!(
"{}/{} user proofs pass the verification. {} fail, the first {} failed proof files: {:?}",
valid_proof_num, proof_file_num, invalid_proof_num, std::cmp::min(invalid_proof_num, invalid_proof_num), invalid_proof_paths.iter().take(max_to_display_valid_proof_num).collect::<Vec<&String>>(),
);
}

if invalid_proof_num > 0 {
return Err(PoRError::InvalidProof);
}
Ok(())
}

pub fn verify_global(global_proof_path: PathBuf) -> Result<(), PoRError> {
pub fn verify_global(global_proof_path: PathBuf, verbose: bool) -> Result<(), PoRError> {
let proof_file = File::open(&global_proof_path).unwrap();
let reader = std::io::BufReader::new(proof_file);

Expand All @@ -97,11 +120,13 @@ pub fn verify_global(global_proof_path: PathBuf) -> Result<(), PoRError> {
get_recursive_circuit_configs::<RECURSION_BRANCHOUT_NUM>(batch_num);

// not to use trace::log to avoid the dependency on the trace config.
println!(
"start to reconstruct the circuit with {} recursive levels for round {}",
recursive_circuit_configs.len(),
round_num
);
if verbose {
println!(
"start to reconstruct the circuit with {} recursive levels for round {}",
recursive_circuit_configs.len(),
round_num
);
}
let start = std::time::Instant::now();
let circuit_registry = CircuitRegistry::<RECURSION_BRANCHOUT_NUM>::init(
batch_size,
Expand All @@ -117,15 +142,24 @@ pub fn verify_global(global_proof_path: PathBuf) -> Result<(), PoRError> {
return Err(PoRError::CircuitDigestMismatch);
}

println!(
"successfully reconstruct the circuit for round {} in {:?}",
round_num,
start.elapsed()
);
if !root_circuit.verify(proof.proof).is_ok() {
return Err(PoRError::InvalidProof);
if verbose {
println!(
"successfully reconstruct the circuit for round {} in {:?}",
round_num,
start.elapsed()
);

let equity = proof.proof.public_inputs
[RecursiveTargets::<RECURSION_BRANCHOUT_NUM>::pub_input_equity_offset()];
let debt = proof.proof.public_inputs
[RecursiveTargets::<RECURSION_BRANCHOUT_NUM>::pub_input_debt_offset()];
if !root_circuit.verify(proof.proof).is_ok() {
return Err(PoRError::InvalidProof);
}

println!("successfully verify the global proof for round {}, total exchange users' equity is {}, debt is {}, exchange liability is {}",
round_num, equity.to_canonical_u64(), debt.to_canonical_u64(), (equity- debt).to_canonical_u64());
}
println!("successfully verify the global proof for round {}", round_num);

Ok(())
}
Loading

0 comments on commit 940b19b

Please sign in to comment.