From 31d8cb14477b99e941361c6caaae3d98d3196652 Mon Sep 17 00:00:00 2001 From: M Alghazwi Date: Thu, 14 Nov 2024 12:26:37 +0100 Subject: [PATCH] fix benchmarks --- README.md | 8 + codex-plonky2-circuits/README.md | 2 +- codex-plonky2-circuits/src/circuits/params.rs | 28 +- proof-input/Cargo.toml | 14 +- proof-input/README.md | 2 +- proof-input/benches/prove_cells.rs | 152 -- proof-input/benches/sample_cells.rs | 129 - proof-input/input.json | 2081 +++++++++++++++++ proof-input/src/json.rs | 4 +- proof-input/src/utils.rs | 8 +- {proof-input => workflow}/BENCHMARKS.md | 0 workflow/Cargo.toml | 14 +- .../benches/safe_circuit.rs | 134 +- workflow/benches/sample_cells.rs | 87 + 14 files changed, 2306 insertions(+), 357 deletions(-) delete mode 100644 proof-input/benches/prove_cells.rs delete mode 100644 proof-input/benches/sample_cells.rs create mode 100644 proof-input/input.json rename {proof-input => workflow}/BENCHMARKS.md (100%) rename {proof-input => workflow}/benches/safe_circuit.rs (51%) create mode 100644 workflow/benches/sample_cells.rs diff --git a/README.md b/README.md index cec5c1a..2a37494 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,12 @@ Repository organization - [`codex-plonky2-circuits`](./codex-plonky2-circuits) contains the codex proof circuits tailored specifically for plonky2. These circuits have the functionality as those in [**here**](https://github.com/codex-storage/codex-storage-proofs-circuits) +- [`proof-input`](./proof-input) contains the lib code to generate proof input for the circuit from fake dataset. + +- [`workflow`](./workflow) contains the scripts and example code to generate input, run the circuits, generate a proof, and verify the proof. + +Documentation +----------------- +To be added soon. + **WARNING**: This repository contains work-in-progress prototypes, and has not received careful code review. It is NOT ready for production use. diff --git a/codex-plonky2-circuits/README.md b/codex-plonky2-circuits/README.md index 83c96e7..56dff6a 100644 --- a/codex-plonky2-circuits/README.md +++ b/codex-plonky2-circuits/README.md @@ -26,4 +26,4 @@ writeup coming soon... see [`workflow`](../workflow) for how to use the circuits and run them. ## Benchmarks -see [`BENCHMARKS.md`](../proof-input/BENCHMARKS.md) +see [`BENCHMARKS.md`](../workflow/BENCHMARKS.md) diff --git a/codex-plonky2-circuits/src/circuits/params.rs b/codex-plonky2-circuits/src/circuits/params.rs index f418951..b7466d0 100644 --- a/codex-plonky2-circuits/src/circuits/params.rs +++ b/codex-plonky2-circuits/src/circuits/params.rs @@ -21,6 +21,26 @@ pub struct CircuitParams{ pub n_samples: usize, } +// hardcoded default constants +const DEFAULT_MAX_DEPTH:usize = 32; +const DEFAULT_MAX_LOG2_N_SLOTS:usize = 8; +const DEFAULT_BLOCK_TREE_DEPTH:usize = 5; +const DEFAULT_N_FIELD_ELEMS_PER_CELL:usize = 272; +const DEFAULT_N_SAMPLES:usize = 5; + +/// Implement the Default trait for Params using the hardcoded constants +impl Default for CircuitParams { + fn default() -> Self { + Self{ + max_depth: DEFAULT_MAX_DEPTH, + max_log2_n_slots: DEFAULT_MAX_LOG2_N_SLOTS, + block_tree_depth: DEFAULT_BLOCK_TREE_DEPTH, + n_field_elems_per_cell: DEFAULT_N_FIELD_ELEMS_PER_CELL, + n_samples: DEFAULT_N_SAMPLES, + } + } +} + impl CircuitParams { /// Creates a new `CircuitParams` struct from environment. /// @@ -32,12 +52,12 @@ impl CircuitParams { /// /// Returns an error if any environment variable is missing or fails to parse. pub fn from_env() -> Result { - let max_depth = env::var("MAX_DEPTH") + let MAX_DEPTH = env::var("MAX_DEPTH") .context("MAX_DEPTH is not set")? .parse::() .context("MAX_DEPTH must be a valid usize")?; - let max_log2_n_slots = env::var("MAX_LOG2_N_SLOTS") + let MAX_LOG2_N_SLOTS = env::var("MAX_LOG2_N_SLOTS") .context("MAX_LOG2_N_SLOTS is not set")? .parse::() .context("MAX_LOG2_N_SLOTS must be a valid usize")?; @@ -58,8 +78,8 @@ impl CircuitParams { .context("N_SAMPLES must be a valid usize")?; Ok(CircuitParams { - max_depth, - max_log2_n_slots, + max_depth: MAX_DEPTH, + max_log2_n_slots: MAX_LOG2_N_SLOTS, block_tree_depth, n_field_elems_per_cell, n_samples, diff --git a/proof-input/Cargo.toml b/proof-input/Cargo.toml index d0016e4..501e91f 100644 --- a/proof-input/Cargo.toml +++ b/proof-input/Cargo.toml @@ -13,16 +13,4 @@ anyhow = "1.0" plonky2 = { version = "0.2.2" } plonky2_field = { version = "0.2.2", default-features = false } plonky2_poseidon2 = { path = "../plonky2_poseidon2" } -codex-plonky2-circuits = { path = "../codex-plonky2-circuits" } - -[[bench]] -name = "safe_circuit" -harness = false - -[[bench]] -name = "prove_cells" -harness = false - -[[bench]] -name = "sample_cells" -harness = false \ No newline at end of file +codex-plonky2-circuits = { path = "../codex-plonky2-circuits" } \ No newline at end of file diff --git a/proof-input/README.md b/proof-input/README.md index 5ce892e..fefb426 100644 --- a/proof-input/README.md +++ b/proof-input/README.md @@ -20,4 +20,4 @@ the [`plonky2 codex proof circuits`](../codex-plonky2-circuits). Currently only see [`workflow`](../workflow) for how to generate proof input. ## Benchmarks -see [`BENCHMARKS.md`](../proof-input/BENCHMARKS.md) +see [`BENCHMARKS.md`](../workflow/BENCHMARKS.md) diff --git a/proof-input/benches/prove_cells.rs b/proof-input/benches/prove_cells.rs deleted file mode 100644 index 20b2914..0000000 --- a/proof-input/benches/prove_cells.rs +++ /dev/null @@ -1,152 +0,0 @@ -use criterion::{criterion_group, criterion_main, Criterion}; -use anyhow::Result; -use std::time::{Duration, Instant}; - -use codex_plonky2_circuits::{ - merkle_tree::merkle_safe::MerkleProof, - circuits::merkle_circuit::MerkleTreeCircuit, -}; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig}; -use plonky2::iop::witness::PartialWitness; -use plonky2::hash::poseidon::PoseidonHash; -use plonky2::field::extension::Extendable; -use plonky2::hash::hash_types::RichField; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use std::marker::PhantomData; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use codex_plonky2_circuits::circuits::prove_single_cell::SlotTreeCircuit; - -macro_rules! pretty_print { - ($($arg:tt)*) => { - print!("\x1b[0;36mINFO ===========>\x1b[0m "); - println!($($arg)*); - } -} - -// Hash function used -type HF = PoseidonHash; - -fn prepare_data< - F: RichField + Extendable + Poseidon2, - C: GenericConfig, - const D: usize, - H: Hasher + AlgebraicHasher, ->(N: usize) -> Result<( - SlotTreeCircuit, - Vec, - Vec>, -)> { - // Initialize the slot tree with default data - let slot_tree = SlotTreeCircuit::::default(); - - // Select N leaf indices to prove - let leaf_indices: Vec = (0..N).collect(); - - // Get the Merkle proofs for the selected leaves - let proofs: Vec<_> = leaf_indices - .iter() - .map(|&leaf_index| slot_tree.get_proof(leaf_index)) - .collect(); - - Ok((slot_tree, leaf_indices, proofs)) -} - -fn build_circuit< - F: RichField + Extendable + Poseidon2, - C: GenericConfig, - const D: usize, - H: Hasher + AlgebraicHasher, ->( - slot_tree: &SlotTreeCircuit, - leaf_indices: &[usize], - proofs: &[MerkleProof], -) -> Result<(CircuitData, PartialWitness)> -{ - // Create the circuit - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - // Create a PartialWitness - let mut pw = PartialWitness::new(); - - // For each proof, create targets, add constraints, and assign witnesses - for (i, &leaf_index) in leaf_indices.iter().enumerate() { - // Build the circuit for each proof - let mut targets = SlotTreeCircuit::::prove_single_cell(&mut builder); - - // Assign witnesses for each proof - slot_tree.single_cell_assign_witness( - &mut pw, - &mut targets, - leaf_index, - &slot_tree.cell_data[leaf_index], - proofs[i].clone(), - )?; - } - - // Build the circuit - let data = builder.build::(); - - Ok((data, pw)) -} - -fn single_cell_proof_benchmark(c: &mut Criterion) { - let mut group = c.benchmark_group("Single Cell Proof Benchmark"); - - // Circuit parameters - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - type H = PoseidonHash; - - // Prepare the data that will be used in all steps - let N = 5; // Number of leaves to prove - let (slot_tree, leaf_indices, proofs) = prepare_data::(N).unwrap(); - - // Benchmark the circuit building - group.bench_function("Single Cell Proof Build", |b| { - b.iter(|| { - build_circuit::(&slot_tree, &leaf_indices, &proofs).unwrap(); - }) - }); - - // Build the circuit - let (data, pw) = build_circuit::(&slot_tree, &leaf_indices, &proofs).unwrap(); - - pretty_print!( - "Circuit size: 2^{} gates", - data.common.degree_bits() - ); - - let start_time = Instant::now(); - let proof_with_pis = data.prove(pw.clone()).unwrap(); - println!("prove_time = {:?}", start_time.elapsed()); - - // Benchmark the proving time - group.bench_function("Single Cell Proof Prove", |b| { - b.iter(|| { - let _proof_with_pis = data.prove(pw.clone()).unwrap(); - }) - }); - - // Generate the proof - let proof_with_pis = data.prove(pw.clone()).unwrap(); - let verifier_data = data.verifier_data(); - - pretty_print!("Proof size: {} bytes", proof_with_pis.to_bytes().len()); - - // Benchmark the verification time - group.bench_function("Single Cell Proof Verify", |b| { - b.iter(|| { - verifier_data.verify(proof_with_pis.clone()).unwrap(); - }) - }); - - group.finish(); -} - -criterion_group!(name = benches; - config = Criterion::default().sample_size(10); - targets = single_cell_proof_benchmark); -criterion_main!(benches); diff --git a/proof-input/benches/sample_cells.rs b/proof-input/benches/sample_cells.rs deleted file mode 100644 index eafc282..0000000 --- a/proof-input/benches/sample_cells.rs +++ /dev/null @@ -1,129 +0,0 @@ -use criterion::{criterion_group, criterion_main, Criterion}; -use anyhow::Result; -use std::time::{Duration, Instant}; -use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig}; -use plonky2::iop::witness::PartialWitness; -use plonky2::hash::poseidon::PoseidonHash; -use plonky2::field::extension::Extendable; -use plonky2::hash::hash_types::RichField; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use codex_plonky2_circuits::circuits::params::TESTING_SLOT_INDEX; -use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit; - -macro_rules! pretty_print { - ($($arg:tt)*) => { - print!("\x1b[0;36mINFO ===========>\x1b[0m "); - println!($($arg)*); - } -} - -// Hash function used -type HF = PoseidonHash; - -fn prepare_data< - F: RichField + Extendable + Poseidon2, - C: GenericConfig, - const D: usize, - H: Hasher + AlgebraicHasher, ->() -> Result<( - SampleCircuit, - usize, - usize, -)> { - // Initialize the dataset tree with testing data - let mut dataset_t = SampleCircuit::::new_for_testing(); - - let slot_index = TESTING_SLOT_INDEX; - let entropy = 123; - - Ok((dataset_t, slot_index, entropy)) -} - -fn build_circuit< - F: RichField + Extendable + Poseidon2, - C: GenericConfig, - const D: usize, - H: Hasher + AlgebraicHasher, ->( - dataset_tree: &mut SampleCircuit, - slot_index: usize, - entropy: usize, - // proofs: &[MerkleProof], -) -> Result<(CircuitData, PartialWitness)> -{ - // Create the circuit - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - - let mut targets = dataset_tree.sample_slot_circuit(&mut builder); - - // Create a PartialWitness - let mut pw = PartialWitness::new(); - dataset_tree.sample_slot_assign_witness(&mut pw, &mut targets,slot_index,entropy); - - // Build the circuit - let data = builder.build::(); - - Ok((data, pw)) -} - -fn sampling_benchmark(c: &mut Criterion) { - let mut group = c.benchmark_group("Sampling Benchmark"); - - // Circuit parameters - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - type H = PoseidonHash; - - // Prepare the data that will be used in all steps - let (mut dataset_tree, slot_index, entropy) = prepare_data::().unwrap(); - - // Benchmark the circuit building - group.bench_function("Single Cell Proof Build", |b| { - b.iter(|| { - build_circuit::(&mut dataset_tree, slot_index, entropy).unwrap(); - }) - }); - - // Build the circuit - let (data, pw) = build_circuit::(&mut dataset_tree, slot_index, entropy).unwrap(); - - pretty_print!( - "Circuit size: 2^{} gates", - data.common.degree_bits() - ); - - let start_time = Instant::now(); - let proof_with_pis = data.prove(pw.clone()).unwrap(); - println!("prove_time = {:?}", start_time.elapsed()); - - // Benchmark the proving time - group.bench_function("Single Cell Proof Prove", |b| { - b.iter(|| { - let _proof_with_pis = data.prove(pw.clone()).unwrap(); - }) - }); - - // Generate the proof - let proof_with_pis = data.prove(pw.clone()).unwrap(); - let verifier_data = data.verifier_data(); - - pretty_print!("Proof size: {} bytes", proof_with_pis.to_bytes().len()); - - // Benchmark the verification time - group.bench_function("Single Cell Proof Verify", |b| { - b.iter(|| { - verifier_data.verify(proof_with_pis.clone()).unwrap(); - }) - }); - - group.finish(); -} - -criterion_group!(name = benches; - config = Criterion::default().sample_size(10); - targets = sampling_benchmark); -criterion_main!(benches); diff --git a/proof-input/input.json b/proof-input/input.json new file mode 100644 index 0000000..14aab8e --- /dev/null +++ b/proof-input/input.json @@ -0,0 +1,2081 @@ +{ + "dataSetRoot": [ + "5518639885900796025", + "11651434580150692677", + "2919112622339430816", + "12056737348926017577" + ], + "entropy": [ + "1234567", + "0", + "0", + "0" + ], + "nCellsPerSlot": 512, + "nSlotsPerDataSet": 11, + "slotIndex": 3, + "slotRoot": [ + "11315349618484427142", + "12341710897639693187", + "5600711137951312864", + "15420562637583941854" + ], + "slotProof": [ + "827439652992611846", + "16905769495525140780", + "16695068033037246276", + "17151630741232149889", + "3469569746364851618", + "18391056527690884511", + "8010039421125473150", + "3408023460182710126", + "12855129173382438132", + "10585118078362511618", + "18326498811560493459", + "4121357915895258498", + "15982493084566743355", + "14593007143866990693", + "14424160485348619", + "291881629905080749", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + "cellData": [ + [ + "1321957732032767503", + "10500621100797814346", + "8531690215172565682", + "8459447812746649108", + "9788667813814183406", + "9474361235712406118", + "7361129800751223466", + "8881658581699219086", + "365488377551015798", + "16305140783085414962", + "2681277102828873415", + "7344344000100747105", + "4766050409648086984", + "6586424234846232203", + "17707338379982931215", + "10059416138115331274", + "680439795278289576", + "15622637166388429026", + "6945035192101195267", + "9242535509532573103", + "11520748470341646395", + "9409387408416325028", + "2857130005175123308", + "16232665935388642411", + "10636520091085850850", + "7797108412180991980", + "12980040556947007729", + "9960727375908433580", + "2303143715938839049", + "12976556020319480417", + "18272559938527115498", + "6223441211499472231", + "12967534592990399513", + "3191694138287921554", + "4696206528413590904", + "102882325161933124", + "12383078293007643478", + "14696777138534280055", + "4814656270340439604", + "9492761601466774396", + "3964878678586747367", + "1478975909110543348", + "16589992140292484216", + "6246116775237220960", + "12610129786127296174", + "2272830133219817428", + "3890384937010596785", + "14313920696655074475", + "11357841953712607745", + "2914090390576690249", + "9467634942008814407", + "12341578641655909839", + "14818941223180832095", + "16222690115599510525", + "15741678007566749794", + "1535904453929081138", + "16604421689130108773", + "1217124242225026018", + "2399301653121298291", + "11778433103224034478", + "8280929921048586777", + "1090435070870820230", + "459984272166288982", + "9631676589448026630", + "4734450181112523741", + "3285917579582468366", + "2289014433122322251", + "9596565658257020041", + "3461143835809092105", + "6239516746903198813", + "3330986343115224086", + "1800835821790039427", + "13584470217981207023", + "10504460184737921656", + "1657011848911774127", + "12662931838561650190", + "3219645777739100624", + "1783726019183667479", + "6376333399791340386", + "14725375767330547198", + "6447509349723982199", + "14398159985293320018", + "2829356812697297464", + "15755379669594543146", + "17060445005716016579", + "17856365217052917833", + "5678038275533231853", + "16021524811467208657", + "10812854270044008521", + "14729505266964236086", + "4217970204585751580", + "7504394123030656222", + "14395099981013033211", + "6442647546949072983", + "237107898723995901", + "15276314867362900457", + "3187146444878016648", + "15556400800712997409", + "2888649869735127729", + "10521745248085189300", + "14657239803489308493", + "694425341799457525", + "3728825593117996372", + "7526183666935933976", + "14924760002961996169", + "10832003686858315462", + "14957183767461080246", + "4886685246027179898", + "2877907061684424380", + "11341990651293264323", + "6948911940417857954", + "15836991807374435511", + "998610698183547598", + "9791607390949942326", + "62637384772698315", + "13885912138387513640", + "13350302107731340890", + "1730434778866949762", + "18237056496264259162", + "15185604050058955239", + "17310985526825417205", + "16326269855554474493", + "12536883363343346082", + "2522619448238609802", + "10558606558842747269", + "12438641753400141413", + "11390432388197433262", + "18186564161298311869", + "12980669591652546861", + "17671050800889020854", + "1324516785338727520", + "7614987191874105497", + "2705410251482268133", + "17969686292881237105", + "4689699006745229919", + "6709332958462023060", + "15071762413290396721", + "1996688519600674082", + "3388766831869121306", + "10028069441058811013", + "5498081041897720880", + "1733608986742723722", + "3751196975802657586", + "2018831175857750468", + "7704987425546505892", + "10208255726720291786", + "6528263720513746869", + "1663392863724276159", + "17935199411150430217", + "3037009734134119797", + "15239832737836716063", + "5105990323692087011", + "17464917878205655394", + "4230049112034857250", + "657038520508180785", + "5212752940367186286", + "3293290327639321824", + "16810845051802093571", + "7129165384473069955", + "15355260984959564246", + "12146977003444469164", + "6570662425913153769", + "2034866294164545305", + "1066361319919207639", + "9715310354947132075", + "18158273814856662321", + "10795812943084242704", + "6494065211846098651", + "17328193797772466532", + "5451855527593549285", + "18421043786740674409", + "15119748423371087384", + "15344701384847628265", + "3434388198274971711", + "9400030205381479777", + "4924698595523803424", + "6319607723358952192", + "1976231541057707246", + "5830207753443937131", + "12100578434916150469", + "7187840945275701918", + "503820489596692661", + "10151880672797977289", + "9652279761126109676", + "16320577389018517354", + "15463021919259386712", + "6256661218966607284", + "731032357113008376", + "87170299657701497", + "2098464815361618678", + "1991630804266842826", + "18131787679808679243", + "9347427447282252478", + "2320873118431962707", + "5883761442003458968", + "10634032908200039268", + "12059341353274332808", + "16058236186418868437", + "8964402196933457120", + "1790223550010348988", + "7434926567046832496", + "5299318689250468243", + "11697924267563364359", + "4850036606362391118", + "9744259628680745009", + "17314578594471040653", + "9910438025536119768", + "3699342726041707387", + "2319831619763457142", + "12140634301356736032", + "9467442254712709930", + "6298244756896955816", + "1213591923250908364", + "3226718675554414795", + "4823342546402755199", + "2386650777942669152", + "9015489454164218174", + "11677813621585967597", + "18295281004016931208", + "3091643561197191771", + "14354117368992650753", + "13804430424840005115", + "15827948724002870171", + "3548699522831384668", + "3198348112214022390", + "11646891205726918685", + "14713543545640374693", + "5654789819153652221", + "6650242772453700638", + "12333982133479157904", + "623283748861372600", + "7093915665096827884", + "3784045436042539716", + "3511067586941905162", + "18333120548938407198", + "4436427294659897172", + "16767965835125054647", + "16110405133238584401", + "8285478621599108921", + "36769715057049911", + "8972533706141673560", + "5822972791581398585", + "4441308886577787816", + "8512544147271187973", + "6582174027054249513", + "4715853251921457376", + "360713355319895280", + "17960627937902838579", + "2968531725101135573", + "11393026208428548959", + "1856325915662815933", + "15090380748396583503", + "13789198951730015529", + "4325010529886295150", + "5089424930266839061", + "17510582375347487643", + "8471654788647306774", + "472890310079065182", + "7578717600596816905", + "5926561338910011182", + "8915040135771781296", + "16103146019075680055", + "18305933536845974043", + "5518822484699853987", + "56227794446124632", + "15980475324613086799", + "14395849954899317", + "10924199351176911518", + "16354466626858319690", + "2947628914659754850", + "7694225292243916417", + "5804346626674108349" + ], + [ + "13838775621435480602", + "8622452602652999519", + "17849228992474488924", + "7561005340066346752", + "7228897092387228363", + "17155824125642247152", + "6703967190968719508", + "16638652947468552788", + "8205651434728790828", + "1237310497541486846", + "2786681180373237513", + "15436767681381713156", + "12327579083760317749", + "12495881476491800626", + "5757445430203580071", + "11645496942535654333", + "553316241417201536", + "13752553651625655092", + "581316695227004350", + "8206944932337873210", + "6505591014278859645", + "1132979180765391826", + "15346894108522791719", + "15013280531016780253", + "6287147491648020287", + "10622370768800869699", + "15674898547514490848", + "11882964752476158504", + "11793486246448175557", + "16893261865984403230", + "13836407358234353956", + "6912042569013694651", + "146729886391272762", + "8704519528167726566", + "8048183351210446242", + "2970371581913780604", + "8722263761283735513", + "16030601780643174643", + "13383202269545521616", + "5263825068007214575", + "8951895167362593092", + "4405839388693939071", + "11663922205351776212", + "1929196107351290245", + "11761649151405803016", + "15593054458551605089", + "9014275741752115561", + "2610752438837880143", + "6691873372028779033", + "12369235598114027744", + "6680705590054177033", + "5598973548307296205", + "9027783081186002356", + "7240291226761189149", + "6410788118789965152", + "1312641011695176545", + "10677754390440958938", + "11798917888663116472", + "12019487674387984185", + "8136608062865716772", + "16353710981095579985", + "13567659206806610509", + "2049880214503544208", + "7749246894908120650", + "594184752109201023", + "1332611154364740526", + "7768864218409398417", + "9542431493544768130", + "11121196967326289805", + "847812506032127795", + "8227529026579097359", + "14497444246438683920", + "1195444420479547571", + "14625755734645833949", + "17964176720263161159", + "1689095822636803589", + "12878308187782372851", + "14976780218678827081", + "2633089215511023124", + "12855068600219289505", + "14086046951786076683", + "7498658847491441428", + "7773600238539379120", + "17230815284399188015", + "2681712130770753775", + "4618918121251572829", + "7341526834347159246", + "17031221373903674709", + "12488076438636956921", + "17865145125531313470", + "543003390768411839", + "12916035453018723169", + "15662026405344487335", + "16923484310233001786", + "9700266273855180333", + "15397334829093407753", + "3037940736442589380", + "5652686216433386581", + "14011028622592724881", + "17523379709215758497", + "595037881073970851", + "7310417371188074661", + "5650719812005387271", + "17459158516941493760", + "10723520100836602546", + "17111889427014472045", + "9709593736689063146", + "5173847515869933336", + "2948616774482221063", + "8253959679887651717", + "16909907443863241049", + "3274412787167477700", + "2131668969294086178", + "6491229515005015268", + "376123993483196749", + "2148250154886783305", + "2704005398962123495", + "6671355393948885836", + "4902058352528510085", + "1165227345709193825", + "4892879897508932007", + "12443534486331999514", + "2717348871466271283", + "17803611028449176608", + "687617522038587829", + "15782779940592085950", + "13603799990727125658", + "568896064488082893", + "9222450923480968956", + "1664685129912600681", + "16927723547285456369", + "7985162001965476266", + "17286029418468258126", + "4399611760236419602", + "3705327341100927100", + "7199934361944188643", + "11989284663055331083", + "5322772019091666356", + "1417771644257238028", + "8332128101225046184", + "12438622775632945690", + "15893336460679317181", + "8983248959157151726", + "12756976521857562222", + "8002320204893999695", + "5469632081981189549", + "3078272508334107230", + "1373323711630055563", + "13863170638347880591", + "1303788206848859967", + "12777797830245998630", + "16671416852743847043", + "11207360217461024199", + "5601933115661008434", + "7154246464791281489", + "5339882662973838210", + "1159837143860261548", + "17511457165776377578", + "8523603169935443051", + "4988045672208317433", + "14378410025580107482", + "145245286334901070", + "15115453512753359870", + "17563822793490120750", + "9616108089059028789", + "12501175846433882661", + "8642609506999429569", + "137788930118871739", + "4979371542171943795", + "6023435829156387413", + "2699089288344058557", + "7311265645531751146", + "1266084593440314207", + "17678871648550264312", + "6961629463950151247", + "7758902079554760537", + "12811458038189171422", + "12279880287929446870", + "2612523009623803475", + "11276121676592323898", + "14040885154374777562", + "12236834630622682237", + "8242475778967316913", + "624107505839474864", + "932525904797298080", + "13862576637837467175", + "11255074412688457156", + "11630573069583038870", + "3965069065731526699", + "9972907682704961979", + "7101987282176358259", + "8568192361271891671", + "11075207250959000750", + "8484414662195091518", + "12147650318917709600", + "12077032599511935891", + "3799944208144310314", + "13176707562049190574", + "4677115864137155721", + "263409026341799527", + "12286840502233472464", + "18207035109171540755", + "1113871373228047313", + "2996583456187333323", + "10491842437955898490", + "11322949563487146502", + "12807038835522504638", + "8002509702311453629", + "8286584038178159845", + "11199469382086739485", + "12011874229285104675", + "13340120761806069193", + "7312471313814930362", + "4730436326786391540", + "14541447408678601898", + "6992347794570956236", + "13958558980790071690", + "5326046650844410085", + "8218512268708231597", + "11982341811522561448", + "4788745045054311255", + "9169847537905870136", + "16275808100267195609", + "2065850986416686620", + "8820520656270174386", + "10851234220746436308", + "17598147149874408668", + "5108357618742691361", + "15707680293231786840", + "9464527687017896157", + "14629826845147138559", + "15884983763533064892", + "5193253493213600980", + "794516428123871156", + "17601873442324843409", + "375676082605319170", + "8102381094018893207", + "89286810794144388", + "66335892495772640", + "14854487172243288172", + "17680732842459941201", + "12791728154770914660", + "1380087527412986090", + "13455491563061171072", + "17483559216826306834", + "7709231170104167764", + "4930190074349546770", + "14209157442508653825", + "1133278365489916579", + "12858830816722410351", + "14111760454217044352", + "1233302912109249362", + "8550988740730883079", + "4914718280443474352", + "7802570622332268026", + "2565585447037144999", + "16500540303611974740", + "3496750188172089297", + "16156906161390637011", + "7919602892385949723", + "2537430878960749281", + "3681748511207551373", + "15346482328223015538", + "8696317218259458451", + "14970576521785409991", + "14182381621452466767", + "2079798940766335808", + "10423507778680402914", + "14514609421605493431", + "9913917150207404050", + "3737792804957316423", + "10768436372801369707" + ], + [ + "5574046383137096909", + "12594176243663775052", + "11264320973306382542", + "7373886875794134178", + "8420620408257337064", + "11535994202858483485", + "11013751025588272818", + "7764555327008215695", + "10925472232532999015", + "12601372122940708109", + "5243323746984830891", + "17327489644273488921", + "14154092754134289192", + "5071335441612074818", + "1577541888188832590", + "7813338443023806107", + "8943250404741275361", + "1680432160114163865", + "10422204537359026825", + "13656006870477494053", + "8232190715151988054", + "12958288904556588433", + "17647855192407984304", + "15138767399820867179", + "13963878469206155116", + "12626972265217109350", + "7783312493376596510", + "8086650163048381512", + "4350354181714990013", + "5495934271598982354", + "18349804108593466589", + "10479798872985594544", + "11699652510733370000", + "2643646666604025522", + "3157015771463289587", + "1221007384104477043", + "6548423985639655169", + "17476360957234089653", + "14162094392953334810", + "13473114712438398496", + "14775854171790198864", + "9331496286778622129", + "1840944405887599999", + "3063527898892648549", + "278490807583103049", + "8903904383342921520", + "17319975515691972839", + "13089709658112737501", + "10114406266824152520", + "15961414588637643681", + "8799038022642731300", + "14118338065161981224", + "3633849016422348804", + "7952763107243526711", + "8240162088433843871", + "13351532606926938705", + "9764089990120755010", + "12394386147655634145", + "11482944563841746913", + "15303615546744416087", + "11848586885966170551", + "9350239651902235093", + "728086486675064164", + "12959327946436631702", + "14371336246247184418", + "3163347377273401294", + "178131551078577431", + "6739503169971173552", + "15034832818325090687", + "10990917959448712227", + "6047457075511093291", + "2344774181153940778", + "3282661763905010941", + "1576206113127274179", + "16438823233010302723", + "17066327430057201429", + "4761616387240135083", + "4266013600360012370", + "1806077789837588663", + "3456846685672989981", + "13952770305993869853", + "10586381433712058670", + "3730106053217047562", + "9049568691932263961", + "13165516203934684802", + "6104283633252592000", + "1886655466140767151", + "7157905408261305709", + "17130585687689744995", + "10352866932111099499", + "6651738171931694893", + "7152788066716600116", + "4470613965421530159", + "8056086418689320251", + "829988346253384003", + "2375456517766326361", + "3081203766972797850", + "12016059923715457936", + "17342053006062612111", + "1348286874789783979", + "15935299863154247279", + "9286771107028131317", + "7601406066547968042", + "18193919775396347800", + "9462544771320056538", + "8523168586995153589", + "1518217201264171306", + "9818589716173406502", + "12139827358293317314", + "332954977261765973", + "12003438101322513590", + "11371033448255627736", + "1571235058260722520", + "17447010947706003064", + "15299070012779111896", + "15430644320213917120", + "16943881247703913628", + "4957104621755352746", + "4401985593764388343", + "14779737224303986812", + "9580409124049472051", + "12550790343903403016", + "11127400152687119333", + "12378066854866438303", + "10170369645381003884", + "12591263706714081582", + "3424410075039994728", + "2150847931630724990", + "12002480383791737021", + "3121318957764689730", + "13362771838555187073", + "10805315240407664500", + "7119382697059623560", + "15650817227778235192", + "17111981663933421888", + "16565756986989728315", + "14394463201367840546", + "16379080033268805470", + "16551004368560132946", + "4958739922543372695", + "12209388508128662131", + "14008180223682408459", + "17222919610817029580", + "3233888860406238538", + "12636837836235779474", + "9400410953935383235", + "8720608361462033443", + "15895445364896716952", + "238266953937351401", + "3782581512740303202", + "14200661329108931237", + "8120390697361361504", + "3003581278618355350", + "5170359993667257985", + "14265855928335087719", + "3620142632167919966", + "277942057850068543", + "14652423436305579867", + "7223750955034738342", + "11489655442406818134", + "3831374684105441123", + "1752618678230720435", + "17080522987480168364", + "1251438322743691402", + "10145396450688348581", + "5062893281898015236", + "15716528759225567495", + "14561284998044551453", + "9369087096175628379", + "16372657437441843220", + "12070571781572412054", + "8620819575544439182", + "9714505436279013910", + "9508688610563210680", + "13216374231737637311", + "3495890601702312760", + "8362426958622137867", + "12636178385465335233", + "3587893316726562608", + "6514805981421906655", + "1707844536745754592", + "1759618114527651877", + "11986316512329473435", + "711927815448237423", + "17703122225053728755", + "10048032640546233628", + "13003524111425814175", + "6277020112433126229", + "6216543814074779486", + "15967741150330933901", + "12700971855681101439", + "7559478057683091578", + "8363809756263018110", + "9152079777842315868", + "13114630842731856498", + "4458029134188817443", + "12447603344359205582", + "5046966115638920467", + "8859391106800105766", + "14628417691226784135", + "6776355381600609342", + "2488362278485066317", + "9290498266392245296", + "3287668470904256429", + "8837131684158429095", + "16872882348506533457", + "5199902885400913924", + "249013569055049681", + "617727972547563785", + "15622799043309250193", + "3496277640846490456", + "2980343827069530207", + "16539919235770881677", + "1734921815021495170", + "5398557170847062725", + "17982145535531836663", + "11972812305652255346", + "8417067994499931024", + "5609081308180235066", + "17749362775208835912", + "18019497139663635305", + "15635122717727942126", + "15131284094535382084", + "3612729231632020483", + "18126419721212087255", + "16391110630978927625", + "11575235139826428548", + "10400054082030569218", + "12234485106313679683", + "15505006044394906862", + "2052438542070005914", + "16310848039468822512", + "11733218812880922822", + "3260412718488861476", + "10322310335803882660", + "5410491022658947446", + "15214939611486897132", + "17551044493427851576", + "6687930471954909501", + "7580984922898671245", + "11786044113754918681", + "18295027407929755826", + "9282461054242038528", + "11607139899570471424", + "5719919289033109057", + "8019542607482016288", + "10925342209926686651", + "13496660593482287", + "10443322532639479554", + "8760402874931871249", + "5548755522219151867", + "3039303454550279863", + "8113269456764174740", + "563947789860266350", + "4225097298986224732", + "3182578936254922612", + "7488045260423103211", + "6525717649284722987", + "154674014711647878", + "17899008265551282999", + "2014813125627679938", + "6561269846711168608", + "5646695690118091478", + "9668342973105800665", + "4787020445374572117", + "5448653229020344072", + "4021099998737776979", + "4764478935774095343", + "356837469739548646", + "5268168479698073057", + "2400614043681511351", + "3532404897602353586" + ], + [ + "10649271511153867533", + "10788862157884985509", + "10137756077416446527", + "14390987917978200379", + "12635918042734942892", + "14534893505473574435", + "320364810869094019", + "1360572352371506753", + "7851239709514165741", + "5565768528467534059", + "4828525389086259897", + "788595101660953824", + "1715769886898676207", + "8372532378778236526", + "18160020900977239486", + "12203105910516427355", + "14694544305141452387", + "10676492866191525192", + "11903407781671164977", + "510270691211612855", + "14448313776429097464", + "3631170197139360195", + "13091051913785139747", + "2600353537112508903", + "12475172801329453070", + "17651462477145535734", + "14940417279306026749", + "724612097106112976", + "714358838809248935", + "4626077745271339030", + "19510515613168735", + "16168028691867079541", + "6793990686636600866", + "1362302680505997181", + "6054692394885623236", + "7205886661617134054", + "1083394054420048736", + "11189505297751906701", + "17571961848550027913", + "7339470193962257232", + "5559522068240842963", + "1841197033509205840", + "12729973957430441873", + "851149086693363912", + "12361718973481993125", + "17798715779008121293", + "5451503984575108377", + "6456139907057115509", + "473314180200743744", + "9339379957078878725", + "13815734755173212697", + "10450981402195851356", + "1065884436524265079", + "10062343003966432797", + "13799180535014183785", + "3669696234335216362", + "13131605566900910931", + "12960961831470203810", + "11328139943522120602", + "1820500261565036156", + "6987696572468905447", + "15190784721266532836", + "9683552835480006989", + "8515890631373571984", + "1503355494911086654", + "9252158760631412929", + "7312424180004913263", + "12395036695742250235", + "18005125795917669145", + "15196975284642381171", + "2235271972135985872", + "10664033018495214683", + "3120960590416624331", + "17436765558331140164", + "18270518624493020348", + "6794783198488915749", + "14968294407982555808", + "6239919398657394253", + "4423601855075873533", + "18197488692919149182", + "5129095873259039171", + "17878056131411670298", + "2211996059084958072", + "9969889634101689520", + "12863903555478688210", + "16628753862695107940", + "13772303005625825935", + "866503797359950452", + "6624815803842176171", + "12891719091677209834", + "4464235611992870035", + "14389046311536218488", + "6811774483893448452", + "8082862725658769451", + "3949926231230302702", + "5159033964938800946", + "10479298395246350622", + "1001074624940385276", + "17873308355701001485", + "13463479950748425987", + "4282721493740801022", + "17315746949651727946", + "15894743228002378405", + "15880105857331223011", + "3629418443272167100", + "6101008831612990398", + "1428647343305539110", + "6822433651942445156", + "13228612772055653156", + "3444163359201457949", + "8274784940221045438", + "6580231411975104611", + "16374765162343717380", + "10212631214319152332", + "6389117833923887366", + "5753641828885535331", + "11136357730245398258", + "17732672285259351512", + "16307440662617327639", + "17405570008561381430", + "3658350923920411597", + "15171746049048568848", + "17329879857066305287", + "5048112786159943549", + "9686483229718540177", + "5165223959359342236", + "5194805798465440405", + "13720605709220156269", + "2690105107631454775", + "6735370021092479208", + "3002461971942438083", + "4456920846590733924", + "17629081678618750428", + "18227619118662246435", + "11224616024162947015", + "14893432138231153234", + "3109667467293364879", + "16277729970723386453", + "5521546563639762681", + "1138733280975148489", + "10656478678691801913", + "14736166323358544400", + "3702623362934743701", + "10343275803885340537", + "15827801296669516451", + "13588382077498216201", + "10515999954243332204", + "15208673867722156668", + "4152754694221529348", + "6056616423714094547", + "9566575511582317922", + "7059116548899342670", + "15581700028421809264", + "2805310965672140724", + "18217070429311575859", + "7883587974547837430", + "3805634045117343986", + "8209521732898334082", + "10931545471543027971", + "2082699937812052576", + "7105560855403681699", + "16156221745766680744", + "17074515628709415009", + "15791951969647264544", + "604596628146570126", + "5259310168063316310", + "7021575435159330721", + "14108430965761838442", + "14553929627531367480", + "14658755913028208471", + "17143041866220370229", + "16275347515631129872", + "9776603760283729591", + "10634485548222411769", + "15547400306063315285", + "2341783062756471694", + "10922376046258584030", + "6867178129196806030", + "12236115918583405601", + "10974898071016393038", + "12603435448748998544", + "1832787035228539861", + "1965281849537775879", + "1218609377873591133", + "18052303714771512139", + "8892760518632460233", + "1806978995794735870", + "16785525404899382467", + "8219063216059028226", + "13435805335838922529", + "4792280652762701795", + "16105414830677565358", + "5364227543746355421", + "13244402995199219900", + "17318490385250796996", + "63313219882807984", + "2924371820537214333", + "5268817556441676580", + "3250455271642042637", + "4807978697425654456", + "5396570144368350075", + "4263584938231078415", + "15646463492285105319", + "7154932800702363331", + "10708958573740174616", + "1892754763003537786", + "16718861444891020880", + "4922912432507464156", + "11110983507324613107", + "14113346784785196909", + "12122285115701952701", + "16512805841524157337", + "1610172776300872983", + "882927013035989105", + "17892690315917838103", + "13539120733144525015", + "15742347246068317854", + "3879822345379777841", + "15451420398628187831", + "3842299739326614234", + "2834573337633445041", + "17500559400445316415", + "12528491380326892055", + "17544696883223051642", + "8653409843432527267", + "8723126451819596743", + "7002450980697150101", + "16518103443400679794", + "9181492601884408250", + "4240260053461237197", + "12276963175033642994", + "8282610389240208238", + "8966803221833797457", + "3477978860017983812", + "10648940961526990278", + "13146959228531138722", + "8324340466958004716", + "18146973163233279889", + "540633068394570200", + "18403046775816854691", + "18037194356141928837", + "8943026189160628685", + "1758617289606752433", + "888418155609099974", + "1601657233197469970", + "11023565340549566139", + "5999499358854857750", + "14335460647931145291", + "9363895425558047734", + "10923594474002362252", + "6561593164309507912", + "17027622241611379413", + "13547070645166304210", + "2076802091008735609", + "6027518054123214818", + "7264778150385833980", + "11000186974886024437", + "5759772710397606386", + "8693251642797975190", + "6563053190947305049", + "14351414717418291422", + "12771365068964279744", + "14770171920652327577", + "10860625094951176953", + "12665300309736370315", + "5287379895299702017", + "17547431994585931028", + "2530685420807667337", + "17960627465896282383", + "4366739477903665328", + "15900948325654321808", + "17602162693049830715" + ], + [ + "904207485077475296", + "1583920456490557062", + "1150581268766663102", + "10160313343671545214", + "10821856184849462395", + "9018207130491147051", + "1389214192257528436", + "6758506447481003257", + "7053120301646131899", + "5942932527373295652", + "7367022006636088911", + "1060793858513796449", + "1297418343821519196", + "1244818856269231912", + "3580794437922699684", + "12732225182137725245", + "9915833436240177659", + "2140594468786765918", + "8605979133437719367", + "3213074983639020881", + "1531412516826417243", + "5125261391792155228", + "249307496826355641", + "15247267981472652986", + "6665047390789544692", + "14722953543868976574", + "16851041846719819676", + "10989207424167528034", + "10743202545696256385", + "18394443129431156482", + "9277746132877951385", + "11324265278081877183", + "1105601309408185597", + "10496229156710011183", + "3045939177720810112", + "16240442202184022837", + "961626679901441577", + "9321953209443819002", + "7212788982855147975", + "6422402484960339924", + "3052909347992690926", + "12056617381879900117", + "8546628762807436166", + "4586702458444354582", + "4177574241628763895", + "5456191925735719812", + "15061754137071891848", + "5918950901290871542", + "8130615244334374967", + "7810726482552389051", + "17958489699746507950", + "10217906067622226255", + "3152704554419057969", + "15252454723121442232", + "8337852962250824193", + "15629137136178011364", + "13233386328753148535", + "6910554744738445275", + "14909992898682766391", + "7492736601572916782", + "5732176703148597453", + "8012160914431488650", + "10750952443393102535", + "7242814158248824015", + "11529581008767818563", + "2949415743556564462", + "11315418149320240967", + "8647048897598810568", + "17685120700407097022", + "15894081997391653315", + "16048579680897710622", + "7082540167124743614", + "7007508524749996017", + "14057009132882421666", + "7222134978347732045", + "5418845430272176040", + "8190832328389716423", + "13804830446672172697", + "16653112171422467877", + "16930381816861644053", + "6433602494001495072", + "6008386712306084702", + "17119447297646122067", + "6292995184571424680", + "18009031790398756656", + "3533855570945326118", + "13925401360636020434", + "5822885843265171062", + "2178170661975596998", + "1890368419649863687", + "4319937846487086218", + "7207875668311269318", + "11791337454640217204", + "17597473174239686357", + "4892935248931343354", + "4076401315364785827", + "14066369866191586591", + "4038766149360549530", + "14450767993652047977", + "2644561601379446529", + "12999064188482912115", + "8393334541523651943", + "5630321696605593187", + "15318652757792352629", + "8422692181496799703", + "4596222562242621808", + "16657774689242944767", + "5027388707581685316", + "6119231734876699910", + "4837833263904054889", + "8540854952163476003", + "519882793309894272", + "6829230766808543972", + "14991557776088579964", + "5705590451927330131", + "13277296153376711501", + "622801892020419275", + "6570132207370186979", + "15528337550680904557", + "17767146993924071531", + "15234269988875332866", + "10158903517508476737", + "3278445321164171411", + "1149900953623464309", + "14644346088084996555", + "1458048012978831881", + "12123640154409654197", + "3846440383385499693", + "1132159947214481745", + "8801430900915021497", + "15703187039688958396", + "11914021957774940465", + "12404327774457720168", + "7665005780191104007", + "4461263301515223411", + "13018393058790143051", + "18116237151362067720", + "5342895121352590487", + "2405457582340958049", + "8002444455855859809", + "8335935765456773721", + "3842806183519100760", + "4076909649609482059", + "14467414370314912014", + "14484665413803436658", + "13309371690632720438", + "3474641644115565279", + "1764483246278609808", + "14941323140115116242", + "17249597483010368367", + "16768350824654493582", + "10562528610722415343", + "8541221236159641588", + "16810342623875493912", + "16691347578457161757", + "7847759968885768464", + "6251705123886750479", + "9027312903158957712", + "1523946009590262797", + "13417040898648202006", + "5996637360697411031", + "3865002006382316408", + "11494913694474819761", + "7851327475489329645", + "1375135461505443190", + "14548439585236499788", + "5362122519923168676", + "18042513292000762821", + "7874120714983395443", + "4603431847633325031", + "11467881237709864468", + "5883970456513508226", + "18022989145134324574", + "8415436183885722865", + "14082190184508190596", + "2611747526383278773", + "7235232063518114351", + "11349744403277490686", + "3076429998180477275", + "1824419687807799592", + "14605325638698136309", + "10370028644950881628", + "158686977840086452", + "10648529985197089440", + "17264501510895158826", + "10963772655196767460", + "11904539515847779417", + "1278173432727850547", + "15473889225945858933", + "8551745411007589018", + "3968221890296689459", + "15801974890821846768", + "17711397323395857261", + "12128899685664837583", + "2771474750808012680", + "5541642480500123531", + "7920575391226747512", + "1604928216461749851", + "16625541978404477585", + "3058479442522640534", + "12900700485081782456", + "12161447996447092526", + "60154919458606523", + "9091903465965457382", + "299245924577187016", + "14779637379988511254", + "13910330543636330366", + "15936006820710490598", + "10815552062332678043", + "11553298151003582038", + "86456658492960426", + "11494000460714418235", + "8303296629276097052", + "12470041829792790375", + "14277526374776841275", + "14388666977538811189", + "6566653201437941086", + "9620924366662034869", + "11803805851611522208", + "14358997333273061176", + "8845851089487850232", + "5374756148816364660", + "9593262145396735390", + "10206839795119357498", + "10052289535783055205", + "9392528752540085321", + "6011886963919469042", + "15971051504509176393", + "4809943263225566676", + "3485517398510898208", + "11781865789949997810", + "15664834620623742652", + "7907615229181845019", + "4932596529367234443", + "3194474671376527632", + "4658737794663307731", + "7377785817531709640", + "5167545431249757586", + "1606053787831262175", + "1882687817289971187", + "12243769603466236255", + "15203908805253445052", + "1892950449313271009", + "18412670811916385920", + "5265929505099216522", + "13060154331361398826", + "6033929693797748627", + "16555567818028310557", + "5554384314328148212", + "10437831352906946283", + "14416747115395601276", + "3768507033038541805", + "18361965083582891963", + "15014049316801078048", + "10983313977909635208", + "15728256940274194410", + "18359091945337566625", + "2920897967448846650", + "10382920880886325005", + "16560395430519998245", + "7646220438919593225", + "4896374807190147215", + "7679811934735453615", + "13478930500400850874", + "15990701461564738536", + "8986342237954561007", + "10147202576022669049", + "16778935240383141653", + "16169014452196079520", + "5479709608285917946", + "14615143938700100313", + "11683365770317392420" + ] + ], + "merklePaths": [ + [ + "10448275262522810265", + "10841630719644310795", + "17304431336591813769", + "16840636975878436052", + "11897841511919568716", + "9752330548452470736", + "17188273636088749548", + "990282636228810685", + "3062519446672617683", + "12473899498614429908", + "9858886373878041223", + "2054422637937037163", + "7009174323309222716", + "2670600433093217806", + "2548688469157815763", + "5672988022701336612", + "1474372584358615624", + "8361844997020951308", + "14213788410110519553", + "11423840486863504659", + "10146179594142962960", + "15028143555662703740", + "15411175473389139231", + "2578264701517641072", + "8932281154121227412", + "5524103726583848571", + "16566847293685373878", + "17042708936102801165", + "1805765449207507961", + "10502574394652409435", + "2032271746061725588", + "14348871333037483836", + "91009594033774023", + "9343745328504739465", + "8968596728757256739", + "6472603758149437965", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "5655633931696033282", + "7021117295955930398", + "7968975292782771264", + "4374962474521932419", + "9548542190870293506", + "9101608973169974310", + "1693964492050520674", + "11197078670977841744", + "16559295969566244036", + "14797307254412256734", + "17420382541500952305", + "317128563867418931", + "4000953869342983573", + "17775996128202812901", + "6655397604307731154", + "11378989531203829648", + "16546447061373168548", + "15949438000657863000", + "7455192016469406622", + "16370193094761380736", + "459233693475879586", + "4879430768791384940", + "8040090128948376940", + "4834842549641379344", + "13565947107498098252", + "5787278307328643059", + "15448298010188789753", + "12980282983655437591", + "10167698252122647674", + "15728861119521577815", + "16216941305753884620", + "13088233271280470274", + "91009594033774023", + "9343745328504739465", + "8968596728757256739", + "6472603758149437965", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "195750093098090966", + "8448571921090255557", + "16913781423735675967", + "10651595577214685614", + "16126308766762411899", + "8428448651381695859", + "16144005943528324614", + "3793126818034117916", + "377105260706743633", + "17231058733488635506", + "18048431597071991815", + "9094520011413248015", + "7308719282632992789", + "9102781806275161575", + "14935199816305355150", + "14977886445803501829", + "4915253945045723276", + "4685916457337819397", + "9427162464406290722", + "3875115830472810647", + "120109681124788684", + "5901041952927369526", + "13225042227769798074", + "7949844496374771936", + "6977413498511592312", + "1004579493061112263", + "9729241372668379239", + "18031307972090260630", + "7533613616925138200", + "8737023005954833219", + "8699404476115027727", + "7114503031457313855", + "10467277522958498837", + "5806338657949390512", + "9980885570318868392", + "8427940607181717468", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "15768402495013816719", + "4813404314734839237", + "14823540469116967983", + "15574115749951027386", + "18414987582926869753", + "8970090286291140917", + "9975612646995514911", + "9674503582159203274", + "7757886477042955784", + "4622226261824685983", + "10245352040364329116", + "10462402258106316172", + "17342747768970019606", + "655328746749976049", + "8303433996335016098", + "16827691236663986774", + "16003240529873190947", + "2844984126198650845", + "185259511589630851", + "4318922195519899594", + "7770148349449877866", + "6789729343435835372", + "101683630019951447", + "16977940480254708201", + "13565947107498098252", + "5787278307328643059", + "15448298010188789753", + "12980282983655437591", + "10167698252122647674", + "15728861119521577815", + "16216941305753884620", + "13088233271280470274", + "91009594033774023", + "9343745328504739465", + "8968596728757256739", + "6472603758149437965", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ], + [ + "5785729852283366699", + "1772800053807930332", + "2170786373325991894", + "16130041813660371410", + "5952669211462286602", + "6375607765960603988", + "9558080061582310621", + "7681468057136458884", + "15514907657946327960", + "16073220387221942650", + "2678038904195172696", + "15107550181701666619", + "6971466711967714323", + "12608510793641961312", + "7990903351125089877", + "14386543215427129580", + "1088912515044640939", + "4454220007742048399", + "13101963415098966295", + "7064955092377859807", + "459233693475879586", + "4879430768791384940", + "8040090128948376940", + "4834842549641379344", + "13565947107498098252", + "5787278307328643059", + "15448298010188789753", + "12980282983655437591", + "10167698252122647674", + "15728861119521577815", + "16216941305753884620", + "13088233271280470274", + "91009594033774023", + "9343745328504739465", + "8968596728757256739", + "6472603758149437965", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ] + ] +} \ No newline at end of file diff --git a/proof-input/src/json.rs b/proof-input/src/json.rs index ebd2956..36d7703 100644 --- a/proof-input/src/json.rs +++ b/proof-input/src/json.rs @@ -326,7 +326,7 @@ mod tests { assert_eq!(original_circ_input, imported_circ_input, "circuit input are not equal"); // cleanup: Remove the generated JSON file - fs::remove_file("input.json")?; + // fs::remove_file("input.json")?; println!("Test passed: Original and imported circuit input are equal."); @@ -383,7 +383,7 @@ mod tests { // reads the json input and verify (non-circuit) // NOTE: expects that the json input proof uses the default params #[test] - fn test_read_json_and_verify() -> anyhow::Result<()> { + fn test_read_json_and_verify() -> Result<()> { let params = TestParams::default(); // Import the circuit input from JSON diff --git a/proof-input/src/utils.rs b/proof-input/src/utils.rs index dd58d74..7840b1c 100644 --- a/proof-input/src/utils.rs +++ b/proof-input/src/utils.rs @@ -13,7 +13,7 @@ use crate::sponge::hash_n_with_padding; // --------- helper functions --------- /// Converts an index to a vector of bits (LSB first) no padding. -pub(crate) fn usize_to_bits_le(index: usize, bit_length: usize) -> Vec { +pub fn usize_to_bits_le(index: usize, bit_length: usize) -> Vec { // Assert that the index can fit within the given bit length. assert!( index < (1 << bit_length), @@ -32,7 +32,7 @@ pub(crate) fn usize_to_bits_le(index: usize, bit_length: usize) -> Vec { } /// returns the first bit_length bits of index -pub(crate) fn low_bits(index: usize, bit_length: usize) -> Vec { +pub fn low_bits(index: usize, bit_length: usize) -> Vec { let mut bits = Vec::with_capacity(bit_length); @@ -46,7 +46,7 @@ pub(crate) fn low_bits(index: usize, bit_length: usize) -> Vec { /// calculate the sampled cell index from entropy, slot root, and counter /// this is the non-circuit version for testing -pub(crate) fn calculate_cell_index_bits< +pub fn calculate_cell_index_bits< F: RichField + Extendable + Poseidon2, const D: usize >(entropy: &Vec, slot_root: HashOut, ctr: usize, depth: usize, mask_bits: Vec) -> Vec { @@ -72,7 +72,7 @@ pub(crate) fn calculate_cell_index_bits< } /// Converts a vector of bits (LSB first) into an index (usize). -pub(crate) fn bits_le_padded_to_usize(bits: &[bool]) -> usize { +pub fn bits_le_padded_to_usize(bits: &[bool]) -> usize { bits.iter().enumerate().fold(0usize, |acc, (i, &bit)| { if bit { acc | (1 << i) diff --git a/proof-input/BENCHMARKS.md b/workflow/BENCHMARKS.md similarity index 100% rename from proof-input/BENCHMARKS.md rename to workflow/BENCHMARKS.md diff --git a/workflow/Cargo.toml b/workflow/Cargo.toml index 6269de7..916fc5a 100644 --- a/workflow/Cargo.toml +++ b/workflow/Cargo.toml @@ -16,6 +16,10 @@ plonky2_poseidon2 = { path = "../plonky2_poseidon2" } codex-plonky2-circuits = { path = "../codex-plonky2-circuits" } proof-input = { path = "../proof-input" } +[dev-dependencies] +criterion = { version = "0.5.1", default-features = false } +tynm = { version = "0.1.6", default-features = false } + [[bin]] name = "prove_and_verify" path = "src/bin/prove_and_verify.rs" @@ -30,4 +34,12 @@ path = "src/bin/build_circ.rs" [[bin]] name = "prove" -path = "src/bin/prove.rs" \ No newline at end of file +path = "src/bin/prove.rs" + +[[bench]] +name = "safe_circuit" +harness = false + +[[bench]] +name = "sample_cells" +harness = false \ No newline at end of file diff --git a/proof-input/benches/safe_circuit.rs b/workflow/benches/safe_circuit.rs similarity index 51% rename from proof-input/benches/safe_circuit.rs rename to workflow/benches/safe_circuit.rs index bc3afcf..bfdc898 100644 --- a/proof-input/benches/safe_circuit.rs +++ b/workflow/benches/safe_circuit.rs @@ -5,15 +5,19 @@ use codex_plonky2_circuits::{merkle_tree::merkle_safe::MerkleTree, circuits::mer use plonky2::field::types::Field; use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData}; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig}; -use plonky2::iop::witness::PartialWitness; -use plonky2::hash::hash_types::HashOut; +use plonky2::iop::witness::{PartialWitness, WitnessWrite}; +use plonky2::hash::hash_types::{HashOut, NUM_HASH_OUT_ELTS}; use plonky2::hash::poseidon::PoseidonHash; use plonky2::field::extension::Extendable; use plonky2::hash::hash_types::RichField; -use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; +use plonky2_poseidon2::poseidon2_hash::poseidon2::{Poseidon2, Poseidon2Hash}; use std::marker::PhantomData; use plonky2::plonk::circuit_builder::CircuitBuilder; use codex_plonky2_circuits::merkle_tree::merkle_safe::MerkleProof; +use plonky2_field::goldilocks_field::GoldilocksField; +use proof_input::tests::merkle_circuit; +use proof_input::tests::merkle_circuit::{assign_witness, MerkleTreeCircuitInput}; +use proof_input::utils::usize_to_bits_le; macro_rules! pretty_print { ($($arg:tt)*) => { @@ -22,37 +26,34 @@ macro_rules! pretty_print { } } -fn prepare_data(N: usize) -> Result<( - MerkleTree, - Vec>, - Vec, - Vec>, +fn prepare_data< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + H: Hasher + AlgebraicHasher, +>(N: usize, max_depth: usize) -> Result<( + Vec>, HashOut, -)> - where - F: RichField + Extendable<2> + Poseidon2, - H: Hasher + AlgebraicHasher + Hasher, -{ - // Total number of leaves in the Merkle tree - let nleaves = 1u64 << 16; - - // Generate leaf data +)> { + // Generate random leaf data + let nleaves = 16; // Number of leaves let data = (0..nleaves) - .map(|i| F::from_canonical_u64(i as u64)) + .map(|i| F::from_canonical_u64(i)) .collect::>(); - // Hash the data to obtain leaf hashes let leaves: Vec> = data .iter() .map(|&element| { + // Hash each field element to get the leaf hash PoseidonHash::hash_no_pad(&[element]) }) .collect(); + //initialize the Merkle tree let zero_hash = HashOut { elements: [F::ZERO; 4], }; - let tree = MerkleTree::::new(&leaves, zero_hash)?; + let tree = MerkleTree::::new(&leaves, zero_hash)?; // Select N leaf indices to prove let leaf_indices: Vec = (0..N).collect(); @@ -63,20 +64,42 @@ fn prepare_data(N: usize) -> Result<( .map(|&leaf_index| tree.get_proof(leaf_index)) .collect::, _>>()?; + let mut circ_inputs = vec![]; + + for i in 0..N{ + let path_bits = usize_to_bits_le(leaf_indices[i], max_depth); + let last_index = (nleaves - 1) as usize; + let last_bits = usize_to_bits_le(last_index, max_depth); + let mask_bits = usize_to_bits_le(last_index, max_depth+1); + + // circuit input + let circuit_input = MerkleTreeCircuitInput::{ + leaf: tree.layers[0][leaf_indices[i]], + path_bits, + last_bits, + mask_bits, + merkle_path: proofs[i].path.clone(), + }; + + circ_inputs.push(circuit_input); + } + // Expected Merkle root let expected_root = tree.root()?; - Ok((tree, leaves, leaf_indices, proofs, expected_root)) + Ok((circ_inputs, expected_root)) } -fn build_circuit( - tree: &MerkleTree, - leaf_indices: &[usize], +fn build_circuit< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + H: Hasher + AlgebraicHasher, +>( + circ_inputs: Vec>, + expected_root: HashOut, + max_depth: usize, ) -> Result<(CircuitData, PartialWitness)> - where - F: RichField + Extendable + Poseidon2, - C: GenericConfig, - H: Hasher + AlgebraicHasher + Hasher, { // Create the circuit let config = CircuitConfig::standard_recursion_config(); @@ -85,19 +108,20 @@ fn build_circuit( // Create a PartialWitness let mut pw = PartialWitness::new(); - // Initialize the circuit instance - let mut circuit_instance = MerkleTreeCircuit:: { - tree: tree.clone(), - _phantom: PhantomData, - }; + for i in 0..circ_inputs.len() { + let (mut targets, reconstructed_root_target) = merkle_circuit::build_circuit(&mut builder, max_depth); - // For each proof, create targets, add constraints, and assign witnesses - for &leaf_index in leaf_indices.iter() { - // Build the circuit for each proof - let (mut targets, _root) = circuit_instance.build_circuit(&mut builder); + // expected Merkle root + let expected_root_target = builder.add_virtual_hash(); - // Assign witnesses for each proof - circuit_instance.assign_witness(&mut pw, &mut targets, leaf_index)?; + // check equality with expected root + for i in 0..NUM_HASH_OUT_ELTS { + builder.connect(expected_root_target.elements[i], reconstructed_root_target.elements[i]); + } + + //assign input + assign_witness(&mut pw, &mut targets, circ_inputs[i].clone())?; + pw.set_hash_target(expected_root_target, expected_root); } // Build the circuit @@ -106,28 +130,28 @@ fn build_circuit( Ok((data, pw)) } -fn merkle_proof_benchmark(c: &mut Criterion) { +fn merkle_proof_benchmark< + F: RichField + Extendable + Poseidon2, + const D: usize, + C: GenericConfig, + H: Hasher + AlgebraicHasher, +>(c: &mut Criterion) { let mut group = c.benchmark_group("Merkle Proof Benchmark"); - // Circuit parameters - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - type H = PoseidonHash; - // Prepare the data that will be used in all steps let N = 5; // Number of leaves to prove - let (tree, _leaves, leaf_indices, _proofs, _expected_root) = prepare_data::(N).unwrap(); + let max_depth = 4; + let (circ_input, expected_root) = prepare_data::(N, max_depth).unwrap(); // Benchmark the circuit building group.bench_function("Merkle Proof Build", |b| { b.iter(|| { - build_circuit::(&tree, &leaf_indices).unwrap(); + build_circuit::(circ_input.clone(), expected_root.clone(), max_depth).unwrap(); }) }); // Build the circuit once to get the data for the proving and verifying steps - let (data, pw) = build_circuit::(&tree, &leaf_indices).unwrap(); + let (data, pw) = build_circuit::(circ_input.clone(), expected_root.clone(), max_depth).unwrap(); pretty_print!( "circuit size: 2^{} gates", @@ -157,8 +181,18 @@ fn merkle_proof_benchmark(c: &mut Criterion) { group.finish(); } +fn run_bench(c: &mut Criterion){ + // Circuit types + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type H = Poseidon2Hash; + + merkle_proof_benchmark::(c); +} + // criterion_group!(benches, merkle_proof_benchmark); criterion_group!(name = benches; config = Criterion::default().sample_size(10); - targets = merkle_proof_benchmark); + targets = run_bench); criterion_main!(benches); diff --git a/workflow/benches/sample_cells.rs b/workflow/benches/sample_cells.rs new file mode 100644 index 0000000..447acd2 --- /dev/null +++ b/workflow/benches/sample_cells.rs @@ -0,0 +1,87 @@ +use anyhow::Result; +use criterion::{criterion_group, criterion_main, Criterion}; +use plonky2::iop::witness::PartialWitness; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::config::GenericConfig; + +use proof_input::json::import_circ_input_from_json; +use codex_plonky2_circuits::circuits::sample_cells::{SampleCircuit, SampleCircuitInput}; +use codex_plonky2_circuits::circuits::params::CircuitParams; +use proof_input::params::{D, C, F, Params}; + +/// Benchmark for building, proving, and verifying the Plonky2 circuit. +fn bench_prove_verify(c: &mut Criterion) { + // get default parameters + let circuit_params = CircuitParams::default(); + + // Import the circuit input from a JSON file + let circ_input: SampleCircuitInput = import_circ_input_from_json("input.json").expect("Failed to import circuit input from JSON"); + println!("Witness imported from input.json"); + + // Create the circuit configuration + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + // Initialize the SampleCircuit with the parameters + let circ = SampleCircuit::new(circuit_params.clone()); + let mut targets = circ.sample_slot_circuit(&mut builder); + + // Create a PartialWitness and assign the circuit input + let mut pw = PartialWitness::new(); + circ.sample_slot_assign_witness(&mut pw, &mut targets, circ_input.clone()); + + // Benchmark Group: Separate benchmarks for building, proving, and verifying + let mut group = c.benchmark_group("Prove and Verify"); + + // Benchmark the Circuit Building Phase + group.bench_function("Build Circuit", |b| { + b.iter(|| { + let config = CircuitConfig::standard_recursion_config(); + let mut local_builder = CircuitBuilder::::new(config); + let local_circ = SampleCircuit::new(circuit_params.clone()); + let mut local_targets = local_circ.sample_slot_circuit(&mut local_builder); + let mut local_pw = PartialWitness::new(); + local_circ.sample_slot_assign_witness(&mut local_pw, &mut local_targets, circ_input.clone()); + let _data = local_builder.build::(); + }) + }); + + // Build the circuit once for proving and verifying benchmarks + let build_start = std::time::Instant::now(); + let data = builder.build::(); + let build_duration = build_start.elapsed(); + println!("Build time: {:?}", build_duration); + println!("Circuit size (degree bits): {:?}", data.common.degree_bits()); + + // Benchmark the Proving Phase + group.bench_function("Prove Circuit", |b| { + b.iter(|| { + let local_pw = pw.clone(); + data.prove(local_pw).expect("Failed to prove circuit") + }) + }); + + // Generate the proof once for verification benchmarking + let proof_with_pis = data.prove(pw.clone()).expect("Failed to prove circuit"); + let verifier_data = data.verifier_data(); + + println!("Proof size: {} bytes", proof_with_pis.to_bytes().len()); + + // Benchmark the Verifying Phase + group.bench_function("Verify Proof", |b| { + b.iter(|| { + verifier_data.verify(proof_with_pis.clone()).expect("Failed to verify proof"); + }) + }); + + group.finish(); +} + +/// Criterion benchmark group +criterion_group!{ + name = prove_verify_benches; + config = Criterion::default().sample_size(10); + targets = bench_prove_verify +} +criterion_main!(prove_verify_benches);